// NewServerHandlerTransport returns a ServerTransport handling gRPC // from inside an http.Handler. It requires that the http Server // supports HTTP/2. func NewServerHandlerTransport(w http.ResponseWriter, r *http.Request) (ServerTransport, error) { if r.ProtoMajor != 2 { return nil, errors.New("gRPC requires HTTP/2") } if r.Method != "POST" { return nil, errors.New("invalid gRPC request method") } if !strings.Contains(r.Header.Get("Content-Type"), "application/grpc") { return nil, errors.New("invalid gRPC request content-type") } if _, ok := w.(http.Flusher); !ok { return nil, errors.New("gRPC requires a ResponseWriter supporting http.Flusher") } if _, ok := w.(http.CloseNotifier); !ok { return nil, errors.New("gRPC requires a ResponseWriter supporting http.CloseNotifier") } st := &serverHandlerTransport{ rw: w, req: r, closedCh: make(chan struct{}), writes: make(chan func()), } if v := r.Header.Get("grpc-timeout"); v != "" { to, err := timeoutDecode(v) if err != nil { return nil, StreamErrorf(codes.Internal, "malformed time-out: %v", err) } st.timeoutSet = true st.timeout = to } var metakv []string for k, vv := range r.Header { k = strings.ToLower(k) if isReservedHeader(k) { continue } for _, v := range vv { if k == "user-agent" { // user-agent is special. Copying logic of http_util.go. if i := strings.LastIndex(v, " "); i == -1 { // There is no application user agent string being set continue } else { v = v[:i] } } metakv = append(metakv, k, v) } } st.headerMD = metadata.Pairs(metakv...) return st, nil }
func (s *testServer) EmptyCall(ctx context.Context, in *testpb.Empty) (*testpb.Empty, error) { if md, ok := metadata.FromContext(ctx); ok { // For testing purpose, returns an error if there is attached metadata other than // the user agent set by the client application. if _, ok := md["user-agent"]; !ok { return nil, grpc.Errorf(codes.DataLoss, "got extra metadata") } var str []string for _, entry := range md["user-agent"] { str = append(str, "ua", entry) } grpc.SendHeader(ctx, metadata.Pairs(str...)) } return new(testpb.Empty), nil }