feat(transport): add transport tls config (#1267)

* add http tls config

* add grpc tls config

* add examples tls

* fix resolver parseTarget

* support https for discovery

* add isSecure
* clean code

Co-authored-by: longXboy <longxboyhi@gmail.com>
Co-authored-by: 包子 <baozhecheng@foxmail.com>
pull/1282/head
Tony Chen 3 years ago committed by GitHub
parent ce0cba4f41
commit 5ca42fe921
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      examples/helloworld/client/main.go
  2. 12
      examples/helloworld/server/main.go
  3. 2
      examples/metadata/client/main.go
  4. 10
      examples/tls/README.md
  5. 64
      examples/tls/cert/server.crt
  6. 51
      examples/tls/cert/server.key
  7. 63
      examples/tls/client/main.go
  8. 63
      examples/tls/server/main.go
  9. 13
      transport/grpc/client.go
  10. 13
      transport/grpc/server.go
  11. 25
      transport/http/client.go
  12. 22
      transport/http/resolver.go
  13. 29
      transport/http/resolver_test.go
  14. 26
      transport/http/server.go

@ -27,6 +27,7 @@ func callHTTP() {
if err != nil { if err != nil {
panic(err) panic(err)
} }
defer conn.Close()
client := pb.NewGreeterHTTPClient(conn) client := pb.NewGreeterHTTPClient(conn)
reply, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "kratos"}) reply, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "kratos"})
if err != nil { if err != nil {
@ -55,6 +56,7 @@ func callGRPC() {
if err != nil { if err != nil {
panic(err) panic(err)
} }
defer conn.Close()
client := pb.NewGreeterClient(conn) client := pb.NewGreeterClient(conn)
reply, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "kratos"}) reply, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "kratos"})
if err != nil { if err != nil {

@ -39,18 +39,18 @@ func (s *server) SayHello(ctx context.Context, in *helloworld.HelloRequest) (*he
func main() { func main() {
s := &server{} s := &server{}
grpcSrv := grpc.NewServer(
grpc.Address(":9000"),
grpc.Middleware(
recovery.Recovery(),
),
)
httpSrv := http.NewServer( httpSrv := http.NewServer(
http.Address(":8000"), http.Address(":8000"),
http.Middleware( http.Middleware(
recovery.Recovery(), recovery.Recovery(),
), ),
) )
grpcSrv := grpc.NewServer(
grpc.Address(":9000"),
grpc.Middleware(
recovery.Recovery(),
),
)
helloworld.RegisterGreeterServer(grpcSrv, s) helloworld.RegisterGreeterServer(grpcSrv, s)
helloworld.RegisterGreeterHTTPServer(httpSrv, s) helloworld.RegisterGreeterHTTPServer(httpSrv, s)

@ -27,6 +27,7 @@ func callHTTP() {
if err != nil { if err != nil {
panic(err) panic(err)
} }
defer conn.Close()
client := helloworld.NewGreeterHTTPClient(conn) client := helloworld.NewGreeterHTTPClient(conn)
ctx := context.Background() ctx := context.Background()
ctx = metadata.AppendToClientContext(ctx, "x-md-global-extra", "2233") ctx = metadata.AppendToClientContext(ctx, "x-md-global-extra", "2233")
@ -48,6 +49,7 @@ func callGRPC() {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
defer conn.Close()
client := helloworld.NewGreeterClient(conn) client := helloworld.NewGreeterClient(conn)
ctx := context.Background() ctx := context.Background()
ctx = metadata.AppendToClientContext(ctx, "x-md-global-extra", "2233") ctx = metadata.AppendToClientContext(ctx, "x-md-global-extra", "2233")

@ -0,0 +1,10 @@
# Run the example
1、Compile and execute the server code:
```shell
$ go run server/main.go
```
2、From a different terminal, compile and execute the client code:
```shell
$ go run client/main.go
```

@ -0,0 +1,64 @@
-----BEGIN CERTIFICATE-----
MIIFZTCCA02gAwIBAgIBATANBgkqhkiG9w0BAQUFADB8MQswCQYDVQQGEwJDTjEL
MAkGA1UECAwCU0gxCzAJBgNVBAcMAlNIMQ8wDQYDVQQKDAZrcmF0b3MxCzAJBgNV
BAsMAklUMRMwEQYDVQQDDAprcmF0b3MuY29tMSAwHgYJKoZIhvcNAQkBFhFrcmF0
b3NAa3JhdG9zLmNvbTAeFw0yMTA3MjcxNTM1MjJaFw0yMjA3MjcxNTM1MjJaME0x
CzAJBgNVBAYTAkNOMQswCQYDVQQIDAJTSDELMAkGA1UEBwwCU0gxDzANBgNVBAoM
BmtyYXRvczETMBEGA1UEAwwKa3JhdG9zLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQAD
ggIPADCCAgoCggIBALfEWAuPqUHTwTiOT8dtiCM3aEm1D7I6K/PY2mSDMMOI4f5z
TYi7LsKLLItMQR44cEDein/kl0U0QNYJRHqVCr/3IXA4ds0maiq+npY/S2KABDiI
Z38TZ1PZ2bcD3Jb0o1gw0GcSokOGzVtuNKSiASc3D711AepGerChD5UrbixrZdg2
wAeWZj39Tl93+zCcldVrCHMSM7LmDluHJ5KZ8T6auuK6ypQPVhqLz8VseHhB/IRw
s9/o9OlJ3kv4wB/CWlFIvU6ZGVnshZAGOk3Brq25kw600RRDr2MpxNhFY1Xvrt7D
tAJ7fK3/3VaV+I2C4OzzmztK7T1WlL8XqZj6I3t1ZCZryMvDIUPzC4mgiRqEJiF7
VzuVm1sjyTKkD4oX6ZjJYXJ/6pbvd8+AexuwVAsQJKqaF1iQC9jThg55RUTkGo8F
DFErW7XHKHe8vKXuRLG5k3xZBiHK7gsVyHzx0ouuSuZMFHg7L9ACeeqtqxqKNd+0
fIo4N0vNb3GEj+YaTLoadhDSBEsynyQNTfrDf+oFRmQUg3q0W4VJHJFhkmTHRRcq
Qj6xEAJDHC1xr8yr3jif9BKWG2+zEbvpiTcRXKhycv2OUI11dK72aMnOycusJjRe
8pOqcYhSVQZnz31WWlkmX9TRiQtEeUUkFCYAnIArSKm5rNwOddLCzC8Z4js1AgMB
AAGjITAfMB0GA1UdEQQWMBSCDCoua3JhdG9zLmNvbYcEfwAAATANBgkqhkiG9w0B
AQUFAAOCAgEAjr3SXzNOcN8+JQuroS6hKHadrcp6djepd3r5YKSEjKBNxVAU0gj6
QGl0zjSqhxSFwN4wCqXU/4JJVOyAJCV+t992j5wNdaGI+Tcu4whK2LtPi0O68ttq
Nn5H/8bmotW0IZ/YDcq1V8EVWiTZPECk4QLx26S2sjG4HOKNUAs8o+PoUmQE5bKJ
XBFWmjsOfPnI0WBGnuCvGUw5wP1ipLiuK+OhoTNKA6SXPopm5KMDv7gjYPlcmPyI
sJcpve75m9EXQxrDvJtvws8MIZnkWvWi7bW6uQ7274S7YjMZL09/sQTolQOtwl59
pvEbkQNPzgdvQYAfrlJjSBtbq3OtHF+j+p2K+7R0TY2F1OW3LeV8vkcq7IOt38Er
FK5feNEL3t9GlrF8ASmJp/JvhWQiJo5tZJxWZ68CjKfLmVd406ehsK5XNlHJemnl
hNpuAegeV6WDglvMNavvQCJfK5mKokn73HujtQveZ8vwPKV4f6Wg3sHJ2yyP7ou2
2UZ10Qbp6UvFYfYuMvLuq8kznapWqQ0dIJzPDs+CzVtjk1eINUF9UjsSvqX4oCvy
+ZvaM9k4kU/fJMRkLstc/Dx2G13T/moI/l5sw0qFtck12zs/SQ7xgcW3b0ruGX9S
11opfl5R86GpXXbz+vNL9fWP+8cIvoGZK8RAC872bcMPEoJPjPIwAbI=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFdDCCA1wCCQDHq+cGa349DzANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJD
TjELMAkGA1UECAwCU0gxCzAJBgNVBAcMAlNIMQ8wDQYDVQQKDAZrcmF0b3MxCzAJ
BgNVBAsMAklUMRMwEQYDVQQDDAprcmF0b3MuY29tMSAwHgYJKoZIhvcNAQkBFhFr
cmF0b3NAa3JhdG9zLmNvbTAeFw0yMTA3MjcxNTMwMzlaFw0zMTA3MjUxNTMwMzla
MHwxCzAJBgNVBAYTAkNOMQswCQYDVQQIDAJTSDELMAkGA1UEBwwCU0gxDzANBgNV
BAoMBmtyYXRvczELMAkGA1UECwwCSVQxEzARBgNVBAMMCmtyYXRvcy5jb20xIDAe
BgkqhkiG9w0BCQEWEWtyYXRvc0BrcmF0b3MuY29tMIICIjANBgkqhkiG9w0BAQEF
AAOCAg8AMIICCgKCAgEApy2GV9MiECuelNk3fz1Qwh6+wj8Ip11NG+LxEGK4/MLD
JRJtbgAg/7s3vzrm4WDKATDO27W6wewNFOvEnGWyh9wyjAtSgnAcJreq7F2DMbpO
+E2guIQHSCCzfa10s4BgwXKdBRPPvwTADIHXPtlbq4BItJqzt/AhLQbdDAp93mHX
NCzFdlIr4wflT2OW7EO24K2LgMZLWCzaESei9fL6AYm7jEvfaFYZksI3rjJNAj1q
wccMu1o6TvdWRA5fvBi6h15Z0ekR8C2LbM1A54zziZwd+YjcwdQHJJgWJFH7yNSt
Oe/AJZzP1nRk/5H0EvxBnF7du6vfeSjZJytp8cXMlbYg4NGGkSy782tBaUaDIb43
iLqSjfHVZDLzbDGNy/u/mzfo4xS8lxZ92zE7z21d0WyUAJ75Z72v4kaNTr2tnMuE
NTTG1787e3NB0CaV6gjeP8XbMV8gwNTrJmTW3dS+DT6sKtTIISOvsUCZ6h5qFvKU
RWqJ7MiaSxg31DPg51caYDjiVLkkES8GRpPM/Njsg9WpFTQeqcecKbbOdw0ihvoV
fq0FgHpp+jbjm0KkmcNdSX7Ld5XeHp2rBPkA283IdXIAvjjthlyWJTmSP6kDDdEI
km4Did1Bg0wcXNnFlbHHavCfeRTQbVoIYVkWH7I323Vp8itvKobz1GirSOK0Hr0C
AwEAATANBgkqhkiG9w0BAQsFAAOCAgEAFBYIOOyABIbUUOjjjvx2FSDRBNLpee5O
45KmznuCGerhR7ad3rUNhaakA9HJzmLMUXtmyzy6+ej0HzdqZE7RRzdDVftBGaOf
thwEzUAiHfqeX0o039sTQvJSqUY2sBko+tyDRmeNtmd3TPE5VZZSWG+TUtrOofr7
K28UquMthJrmtSC8IJQOvA78Nc/FCPNaGZrcS8ZvrgbrkCLPN4dIJvY9I38xaWQ+
G0gNQazxPzdp89/UMzkczyJAKjYj4JyLCbrjzTZXjtu+rYJezxyS+3QSf0F0xVBr
/8HCeXX6xG16WZY54Z6AijqI3sjiRBSQ25rLJJ00sWa9k1oH0Poyiv4pQG3RHgIs
jJEQh7RQE5zAsBx2NHZ8FcsUGX2oOjSS+vtX//Bg37kN7oYx5HEtK9c+a0wWUxo8
8cqIzqrQSWOd1CipxbE5CUUNKdGQzNCLTfLO68KitLdaSOCGoU/PaoAncbr6EjdB
kzqJcHooqq8asl6fu1DVnYqCpEEp30ldU3p4MdclcMV0XZUq6bXFq1ylmfZXfC0t
zSGnBUjxB5lohn5fs1S/DxyoUR8LbIFVWCljEf4jJtMRnCQV3bR3xeVTbGh3ti81
21uhQKjIP/X2BRNAvRo1qUbrzEeHAJG3EbIG78rRFvSz6MkWVTZzeH1SgCr9Onw7
djovWE7E6ic=
-----END CERTIFICATE-----

@ -0,0 +1,51 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

@ -0,0 +1,63 @@
package main
import (
"context"
"crypto/tls"
"crypto/x509"
"io/ioutil"
"log"
pb "github.com/go-kratos/kratos/examples/helloworld/helloworld"
"github.com/go-kratos/kratos/v2/transport/grpc"
"github.com/go-kratos/kratos/v2/transport/http"
)
func main() {
b, err := ioutil.ReadFile("../cert/server.crt")
if err != nil {
panic(err)
}
cp := x509.NewCertPool()
if !cp.AppendCertsFromPEM(b) {
panic(err)
}
tlsConf := &tls.Config{ServerName: "www.kratos.com", RootCAs: cp}
callHTTP(tlsConf)
callGRPC(tlsConf)
}
func callHTTP(tlsConf *tls.Config) {
conn, err := http.NewClient(
context.Background(),
http.WithEndpoint("https://127.0.0.1:8000"),
http.WithTLSConfig(tlsConf),
)
if err != nil {
panic(err)
}
defer conn.Close()
client := pb.NewGreeterHTTPClient(conn)
reply, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "kratos"})
if err != nil {
log.Fatal(err)
}
log.Printf("[http] SayHello %s\n", reply.Message)
}
func callGRPC(tlsConf *tls.Config) {
conn, err := grpc.Dial(
context.Background(),
grpc.WithEndpoint("127.0.0.1:9000"),
grpc.WithTLSConfig(tlsConf),
)
if err != nil {
panic(err)
}
defer conn.Close()
client := pb.NewGreeterClient(conn)
reply, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "kratos"})
if err != nil {
log.Fatal(err)
}
log.Printf("[grpc] SayHello %+v\n", reply)
}

@ -0,0 +1,63 @@
package main
import (
"context"
"crypto/tls"
"fmt"
"log"
"github.com/go-kratos/kratos/examples/helloworld/helloworld"
"github.com/go-kratos/kratos/v2"
"github.com/go-kratos/kratos/v2/transport/grpc"
"github.com/go-kratos/kratos/v2/transport/http"
)
// go build -ldflags "-X main.Version=x.y.z"
var (
// Name is the name of the compiled software.
Name = "helloworld"
// Version is the version of the compiled software.
Version = "v1.0.0"
)
// server is used to implement helloworld.GreeterServer.
type server struct {
helloworld.UnimplementedGreeterServer
}
// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *helloworld.HelloRequest) (*helloworld.HelloReply, error) {
return &helloworld.HelloReply{Message: fmt.Sprintf("Hello %+v", in.Name)}, nil
}
func main() {
cert, err := tls.LoadX509KeyPair("../cert/server.crt", "../cert/server.key")
if err != nil {
panic(err)
}
tlsConf := &tls.Config{Certificates: []tls.Certificate{cert}}
s := &server{}
httpSrv := http.NewServer(
http.Address(":8000"),
http.TLSConfig(tlsConf),
)
grpcSrv := grpc.NewServer(
grpc.Address(":9000"),
grpc.TLSConfig(tlsConf),
)
helloworld.RegisterGreeterServer(grpcSrv, s)
helloworld.RegisterGreeterHTTPServer(httpSrv, s)
app := kratos.New(
kratos.Name(Name),
kratos.Server(
httpSrv,
grpcSrv,
),
)
if err := app.Run(); err != nil {
log.Fatal(err)
}
}

@ -2,6 +2,7 @@ package grpc
import ( import (
"context" "context"
"crypto/tls"
"time" "time"
"github.com/go-kratos/kratos/v2/middleware" "github.com/go-kratos/kratos/v2/middleware"
@ -14,6 +15,7 @@ import (
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/balancer/roundrobin" "google.golang.org/grpc/balancer/roundrobin"
"google.golang.org/grpc/credentials"
grpcmd "google.golang.org/grpc/metadata" grpcmd "google.golang.org/grpc/metadata"
) )
@ -48,6 +50,13 @@ func WithDiscovery(d registry.Discovery) ClientOption {
} }
} }
// WithTLSConfig with TLS config.
func WithTLSConfig(c *tls.Config) ClientOption {
return func(o *clientOptions) {
o.tlsConf = c
}
}
// WithUnaryInterceptor returns a DialOption that specifies the interceptor for unary RPCs. // WithUnaryInterceptor returns a DialOption that specifies the interceptor for unary RPCs.
func WithUnaryInterceptor(in ...grpc.UnaryClientInterceptor) ClientOption { func WithUnaryInterceptor(in ...grpc.UnaryClientInterceptor) ClientOption {
return func(o *clientOptions) { return func(o *clientOptions) {
@ -65,6 +74,7 @@ func WithOptions(opts ...grpc.DialOption) ClientOption {
// clientOptions is gRPC Client // clientOptions is gRPC Client
type clientOptions struct { type clientOptions struct {
endpoint string endpoint string
tlsConf *tls.Config
timeout time.Duration timeout time.Duration
discovery registry.Discovery discovery registry.Discovery
middleware []middleware.Middleware middleware []middleware.Middleware
@ -106,6 +116,9 @@ func dial(ctx context.Context, insecure bool, opts ...ClientOption) (*grpc.Clien
if insecure { if insecure {
grpcOpts = append(grpcOpts, grpc.WithInsecure()) grpcOpts = append(grpcOpts, grpc.WithInsecure())
} }
if options.tlsConf != nil {
grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(credentials.NewTLS(options.tlsConf)))
}
if len(options.grpcOpts) > 0 { if len(options.grpcOpts) > 0 {
grpcOpts = append(grpcOpts, options.grpcOpts...) grpcOpts = append(grpcOpts, options.grpcOpts...)
} }

@ -2,6 +2,7 @@ package grpc
import ( import (
"context" "context"
"crypto/tls"
"net" "net"
"net/url" "net/url"
"sync" "sync"
@ -15,6 +16,7 @@ import (
"github.com/go-kratos/kratos/v2/transport" "github.com/go-kratos/kratos/v2/transport"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/health" "google.golang.org/grpc/health"
"google.golang.org/grpc/health/grpc_health_v1" "google.golang.org/grpc/health/grpc_health_v1"
grpcmd "google.golang.org/grpc/metadata" grpcmd "google.golang.org/grpc/metadata"
@ -62,6 +64,13 @@ func Middleware(m ...middleware.Middleware) ServerOption {
} }
} }
// TLSConfig with TLS config.
func TLSConfig(c *tls.Config) ServerOption {
return func(s *Server) {
s.tlsConf = c
}
}
// UnaryInterceptor returns a ServerOption that sets the UnaryServerInterceptor for the server. // UnaryInterceptor returns a ServerOption that sets the UnaryServerInterceptor for the server.
func UnaryInterceptor(in ...grpc.UnaryServerInterceptor) ServerOption { func UnaryInterceptor(in ...grpc.UnaryServerInterceptor) ServerOption {
return func(s *Server) { return func(s *Server) {
@ -80,6 +89,7 @@ func Options(opts ...grpc.ServerOption) ServerOption {
type Server struct { type Server struct {
*grpc.Server *grpc.Server
ctx context.Context ctx context.Context
tlsConf *tls.Config
lis net.Listener lis net.Listener
once sync.Once once sync.Once
err error err error
@ -116,6 +126,9 @@ func NewServer(opts ...ServerOption) *Server {
var grpcOpts = []grpc.ServerOption{ var grpcOpts = []grpc.ServerOption{
grpc.ChainUnaryInterceptor(ints...), grpc.ChainUnaryInterceptor(ints...),
} }
if srv.tlsConf != nil {
grpcOpts = append(grpcOpts, grpc.Creds(credentials.NewTLS(srv.tlsConf)))
}
if len(srv.grpcOpts) > 0 { if len(srv.grpcOpts) > 0 {
grpcOpts = append(grpcOpts, srv.grpcOpts...) grpcOpts = append(grpcOpts, srv.grpcOpts...)
} }

@ -3,6 +3,7 @@ package http
import ( import (
"bytes" "bytes"
"context" "context"
"crypto/tls"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
@ -35,6 +36,7 @@ type ClientOption func(*clientOptions)
// Client is an HTTP transport client. // Client is an HTTP transport client.
type clientOptions struct { type clientOptions struct {
ctx context.Context ctx context.Context
tlsConf *tls.Config
timeout time.Duration timeout time.Duration
endpoint string endpoint string
userAgent string userAgent string
@ -127,6 +129,13 @@ func WithBlock() ClientOption {
} }
} }
// WithTLSConfig with tls config.
func WithTLSConfig(c *tls.Config) ClientOption {
return func(o *clientOptions) {
o.tlsConf = c
}
}
// Client is an HTTP client. // Client is an HTTP client.
type Client struct { type Client struct {
opts clientOptions opts clientOptions
@ -149,7 +158,16 @@ func NewClient(ctx context.Context, opts ...ClientOption) (*Client, error) {
for _, o := range opts { for _, o := range opts {
o(&options) o(&options)
} }
target, err := parseTarget(options.endpoint) if options.tlsConf != nil {
if tr, ok := options.transport.(*http.Transport); ok {
tr.TLSClientConfig = options.tlsConf
}
}
var isSecure bool
if options.tlsConf != nil {
isSecure = true
}
target, err := parseTarget(options.endpoint, isSecure)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -285,7 +303,10 @@ func (client *Client) do(ctx context.Context, req *http.Request, c callInfo) (*h
// Close tears down the Transport and all underlying connections. // Close tears down the Transport and all underlying connections.
func (client *Client) Close() error { func (client *Client) Close() error {
return client.r.Close() if client.r != nil {
return client.r.Close()
}
return nil
} }
// DefaultRequestEncoder is an HTTP request encoder. // DefaultRequestEncoder is an HTTP request encoder.

@ -4,6 +4,8 @@ import (
"context" "context"
"errors" "errors"
"net/url" "net/url"
"strconv"
"strings"
"sync" "sync"
"time" "time"
@ -23,12 +25,17 @@ type Target struct {
Endpoint string Endpoint string
} }
func parseTarget(endpoint string) (*Target, error) { func parseTarget(endpoint string, isSecure bool) (*Target, error) {
if !strings.Contains(endpoint, "://") {
if isSecure {
endpoint = "https://" + endpoint
} else {
endpoint = "http://" + endpoint
}
}
u, err := url.Parse(endpoint) u, err := url.Parse(endpoint)
if err != nil { if err != nil {
if u, err = url.Parse("http://" + endpoint); err != nil { return nil, err
return nil, err
}
} }
target := &Target{Scheme: u.Scheme, Authority: u.Host} target := &Target{Scheme: u.Scheme, Authority: u.Host}
if len(u.Path) > 1 { if len(u.Path) > 1 {
@ -139,7 +146,12 @@ func parseEndpoint(endpoints []string) (string, string, error) {
return "", "", err return "", "", err
} }
if u.Scheme == "http" { if u.Scheme == "http" {
return u.Scheme, u.Host, nil isSecure, _ := strconv.ParseBool(u.Query().Get("isSecure"))
scheme := "http"
if isSecure {
scheme = "https"
}
return scheme, u.Host, nil
} }
} }
return "", "", nil return "", "", nil

@ -0,0 +1,29 @@
package http
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestParseTarget(t *testing.T) {
target, err := parseTarget("localhost:8000", false)
assert.Nil(t, err)
assert.Equal(t, &Target{Scheme: "http", Authority: "localhost:8000"}, target)
target, err = parseTarget("discovery:///demo", false)
assert.Nil(t, err)
assert.Equal(t, &Target{Scheme: "discovery", Authority: "", Endpoint: "demo"}, target)
target, err = parseTarget("127.0.0.1:8000", false)
assert.Nil(t, err)
assert.Equal(t, &Target{Scheme: "http", Authority: "127.0.0.1:8000"}, target)
target, err = parseTarget("https://127.0.0.1:8000", false)
assert.Nil(t, err)
assert.Equal(t, &Target{Scheme: "https", Authority: "127.0.0.1:8000"}, target)
target, err = parseTarget("127.0.0.1:8000", true)
assert.Nil(t, err)
assert.Equal(t, &Target{Scheme: "https", Authority: "127.0.0.1:8000"}, target)
}

@ -2,6 +2,7 @@ package http
import ( import (
"context" "context"
"crypto/tls"
"errors" "errors"
"net" "net"
"net/http" "net/http"
@ -93,10 +94,18 @@ func Endpoint(endpoint *url.URL) ServerOption {
} }
} }
// TLSConfig with TLS config.
func TLSConfig(c *tls.Config) ServerOption {
return func(o *Server) {
o.tlsConf = c
}
}
// Server is an HTTP server wrapper. // Server is an HTTP server wrapper.
type Server struct { type Server struct {
*http.Server *http.Server
lis net.Listener lis net.Listener
tlsConf *tls.Config
once sync.Once once sync.Once
endpoint *url.URL endpoint *url.URL
err error err error
@ -127,7 +136,8 @@ func NewServer(opts ...ServerOption) *Server {
o(srv) o(srv)
} }
srv.Server = &http.Server{ srv.Server = &http.Server{
Handler: FilterChain(srv.filters...)(srv), Handler: FilterChain(srv.filters...)(srv),
TLSConfig: srv.tlsConf,
} }
srv.router = mux.NewRouter() srv.router = mux.NewRouter()
srv.router.Use(srv.filter()) srv.router.Use(srv.filter())
@ -207,7 +217,11 @@ func (s *Server) Endpoint() (*url.URL, error) {
return return
} }
s.lis = lis s.lis = lis
s.endpoint = &url.URL{Scheme: "http", Host: addr} var query string
if s.tlsConf != nil {
query = "isSecure=true"
}
s.endpoint = &url.URL{Scheme: "http", Host: addr, RawQuery: query}
}) })
if s.err != nil { if s.err != nil {
return nil, s.err return nil, s.err
@ -224,7 +238,13 @@ func (s *Server) Start(ctx context.Context) error {
return ctx return ctx
} }
s.log.Infof("[HTTP] server listening on: %s", s.lis.Addr().String()) s.log.Infof("[HTTP] server listening on: %s", s.lis.Addr().String())
if err := s.Serve(s.lis); !errors.Is(err, http.ErrServerClosed) { var err error
if s.tlsConf != nil {
err = s.ServeTLS(s.lis, "", "")
} else {
err = s.Serve(s.lis)
}
if !errors.Is(err, http.ErrServerClosed) {
return err return err
} }
return nil return nil

Loading…
Cancel
Save