NewServerHandlerTransport returns a ServerTransport handling gRPC from inside an http.Handler, or writes an HTTP error to w and returns an error. It requires that the http Server supports HTTP/2.
(w http.ResponseWriter, r *http.Request, stats stats.Handler, bufferPool mem.BufferPool)
| 51 | // inside an http.Handler, or writes an HTTP error to w and returns an error. |
| 52 | // It requires that the http Server supports HTTP/2. |
| 53 | func NewServerHandlerTransport(w http.ResponseWriter, r *http.Request, stats stats.Handler, bufferPool mem.BufferPool) (ServerTransport, error) { |
| 54 | if r.Method != http.MethodPost { |
| 55 | w.Header().Set("Allow", http.MethodPost) |
| 56 | msg := fmt.Sprintf("invalid gRPC request method %q", r.Method) |
| 57 | http.Error(w, msg, http.StatusMethodNotAllowed) |
| 58 | return nil, errors.New(msg) |
| 59 | } |
| 60 | contentType := r.Header.Get("Content-Type") |
| 61 | // TODO: do we assume contentType is lowercase? we did before |
| 62 | contentSubtype, validContentType := grpcutil.ContentSubtype(contentType) |
| 63 | if !validContentType { |
| 64 | msg := fmt.Sprintf("invalid gRPC request content-type %q", contentType) |
| 65 | http.Error(w, msg, http.StatusUnsupportedMediaType) |
| 66 | return nil, errors.New(msg) |
| 67 | } |
| 68 | if r.ProtoMajor != 2 { |
| 69 | msg := "gRPC requires HTTP/2" |
| 70 | http.Error(w, msg, http.StatusHTTPVersionNotSupported) |
| 71 | return nil, errors.New(msg) |
| 72 | } |
| 73 | if _, ok := w.(http.Flusher); !ok { |
| 74 | msg := "gRPC requires a ResponseWriter supporting http.Flusher" |
| 75 | http.Error(w, msg, http.StatusInternalServerError) |
| 76 | return nil, errors.New(msg) |
| 77 | } |
| 78 | |
| 79 | var localAddr net.Addr |
| 80 | if la := r.Context().Value(http.LocalAddrContextKey); la != nil { |
| 81 | localAddr, _ = la.(net.Addr) |
| 82 | } |
| 83 | var authInfo credentials.AuthInfo |
| 84 | if r.TLS != nil { |
| 85 | authInfo = credentials.TLSInfo{State: *r.TLS, CommonAuthInfo: credentials.CommonAuthInfo{SecurityLevel: credentials.PrivacyAndIntegrity}} |
| 86 | } |
| 87 | p := peer.Peer{ |
| 88 | Addr: strAddr(r.RemoteAddr), |
| 89 | LocalAddr: localAddr, |
| 90 | AuthInfo: authInfo, |
| 91 | } |
| 92 | st := &serverHandlerTransport{ |
| 93 | rw: w, |
| 94 | req: r, |
| 95 | closedCh: make(chan struct{}), |
| 96 | writes: make(chan func()), |
| 97 | peer: p, |
| 98 | contentType: contentType, |
| 99 | contentSubtype: contentSubtype, |
| 100 | stats: stats, |
| 101 | bufferPool: bufferPool, |
| 102 | } |
| 103 | st.logger = prefixLoggerForServerHandlerTransport(st) |
| 104 | |
| 105 | if v := r.Header.Get("grpc-timeout"); v != "" { |
| 106 | to, err := decodeTimeout(v) |
| 107 | if err != nil { |
| 108 | msg := fmt.Sprintf("malformed grpc-timeout: %v", err) |
| 109 | http.Error(w, msg, http.StatusBadRequest) |
| 110 | return nil, status.Error(codes.Internal, msg) |