1package grpc // import "github.com/docker/docker/api/server/router/grpc"
2
3import (
4	"context"
5	"net/http"
6
7	"github.com/pkg/errors"
8	"golang.org/x/net/http2"
9)
10
11func (gr *grpcRouter) serveGRPC(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
12	h, ok := w.(http.Hijacker)
13	if !ok {
14		return errors.New("handler does not support hijack")
15	}
16	proto := r.Header.Get("Upgrade")
17	if proto == "" {
18		return errors.New("no upgrade proto in request")
19	}
20	if proto != "h2c" {
21		return errors.Errorf("protocol %s not supported", proto)
22	}
23
24	conn, _, err := h.Hijack()
25	if err != nil {
26		return err
27	}
28	resp := &http.Response{
29		StatusCode: http.StatusSwitchingProtocols,
30		ProtoMajor: 1,
31		ProtoMinor: 1,
32		Header:     http.Header{},
33	}
34	resp.Header.Set("Connection", "Upgrade")
35	resp.Header.Set("Upgrade", proto)
36
37	// set raw mode
38	conn.Write([]byte{})
39	resp.Write(conn)
40
41	// https://godoc.org/golang.org/x/net/http2#Server.ServeConn
42	// TODO: is it a problem that conn has already been written to?
43	gr.h2Server.ServeConn(conn, &http2.ServeConnOpts{Handler: gr.grpcServer})
44	return nil
45}
46