@@ -17,6 +17,7 @@ import (
1717 "github.com/prometheus/client_golang/prometheus"
1818 "github.com/prometheus/client_golang/prometheus/promhttp"
1919 "github.com/prometheus/exporter-toolkit/web"
20+ "github.com/soheilhy/cmux"
2021 "golang.org/x/net/context"
2122 "golang.org/x/net/netutil"
2223 "google.golang.org/grpc"
@@ -96,6 +97,7 @@ type Config struct {
9697 HTTPMiddleware []middleware.Interface `yaml:"-"`
9798 Router * mux.Router `yaml:"-"`
9899 DoNotAddDefaultHTTPMiddleware bool `yaml:"-"`
100+ RouteHTTPToGRPC bool `yaml:"-"`
99101
100102 GPRCServerMaxRecvMsgSize int `yaml:"grpc_server_max_recv_msg_size"`
101103 GRPCServerMaxSendMsgSize int `yaml:"grpc_server_max_send_msg_size"`
@@ -185,6 +187,13 @@ type Server struct {
185187 grpcListener net.Listener
186188 httpListener net.Listener
187189
190+ // These fields are used to support grpc over the http server
191+ // if RouteHTTPToGRPC is set. the fields are kept here
192+ // so they can be initialized in New() and started in Run()
193+ grpchttpmux cmux.CMux
194+ grpcOnHTTPListener net.Listener
195+ GRPCOnHTTPServer * grpc.Server
196+
188197 HTTP * mux.Router
189198 HTTPServer * http.Server
190199 GRPC * grpc.Server
@@ -242,6 +251,15 @@ func New(cfg Config) (*Server, error) {
242251 httpListener = netutil .LimitListener (httpListener , cfg .HTTPConnLimit )
243252 }
244253
254+ var grpcOnHTTPListener net.Listener
255+ var grpchttpmux cmux.CMux
256+ if cfg .RouteHTTPToGRPC {
257+ grpchttpmux = cmux .New (httpListener )
258+
259+ httpListener = grpchttpmux .Match (cmux .HTTP1Fast ())
260+ grpcOnHTTPListener = grpchttpmux .Match (cmux .HTTP2 ())
261+ }
262+
245263 network = cfg .GRPCListenNetwork
246264 if network == "" {
247265 network = DefaultNetwork
@@ -384,6 +402,7 @@ func New(cfg Config) (*Server, error) {
384402 grpcOptions = append (grpcOptions , grpc .Creds (grpcCreds ))
385403 }
386404 grpcServer := grpc .NewServer (grpcOptions ... )
405+ grpcOnHttpServer := grpc .NewServer (grpcOptions ... )
387406
388407 // Setup HTTP server
389408 var router * mux.Router
@@ -446,17 +465,20 @@ func New(cfg Config) (*Server, error) {
446465 }
447466
448467 return & Server {
449- cfg : cfg ,
450- httpListener : httpListener ,
451- grpcListener : grpcListener ,
452- handler : handler ,
453-
454- HTTP : router ,
455- HTTPServer : httpServer ,
456- GRPC : grpcServer ,
457- Log : log ,
458- Registerer : reg ,
459- Gatherer : gatherer ,
468+ cfg : cfg ,
469+ httpListener : httpListener ,
470+ grpcListener : grpcListener ,
471+ grpcOnHTTPListener : grpcOnHTTPListener ,
472+ handler : handler ,
473+ grpchttpmux : grpchttpmux ,
474+
475+ HTTP : router ,
476+ HTTPServer : httpServer ,
477+ GRPC : grpcServer ,
478+ GRPCOnHTTPServer : grpcOnHttpServer ,
479+ Log : log ,
480+ Registerer : reg ,
481+ Gatherer : gatherer ,
460482 }, nil
461483}
462484
@@ -509,19 +531,37 @@ func (s *Server) Run() error {
509531
510532 go func () {
511533 err := s .GRPC .Serve (s .grpcListener )
512- if err == grpc .ErrServerStopped {
513- err = nil
514- }
515-
516- select {
517- case errChan <- err :
518- default :
519- }
534+ handleGRPCError (err , errChan )
520535 }()
521536
537+ // grpchttpmux will only be set if grpchttpmux RouteHTTPToGRPC is set
538+ if s .grpchttpmux != nil {
539+ go func () {
540+ err := s .grpchttpmux .Serve ()
541+ handleGRPCError (err , errChan )
542+ }()
543+ go func () {
544+ err := s .GRPCOnHTTPServer .Serve (s .grpcOnHTTPListener )
545+ handleGRPCError (err , errChan )
546+ }()
547+ }
548+
522549 return <- errChan
523550}
524551
552+ // handleGRPCError consolidates GRPC Server error handling by sending
553+ // any error to errChan except for grpc.ErrServerStopped which is ignored.
554+ func handleGRPCError (err error , errChan chan error ) {
555+ if err == grpc .ErrServerStopped {
556+ err = nil
557+ }
558+
559+ select {
560+ case errChan <- err :
561+ default :
562+ }
563+ }
564+
525565// HTTPListenAddr exposes `net.Addr` that `Server` is listening to for HTTP connections.
526566func (s * Server ) HTTPListenAddr () net.Addr {
527567 return s .httpListener .Addr ()
0 commit comments