2 * Copyright 2016, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 // This file is the implementation of a gRPC server using HTTP/2 which
34 // uses the standard Go http2 Server implementation (via the
35 // http.Handler interface), rather than speaking low-level HTTP/2
36 // frames itself. It is the implementation of *grpc.Server.ServeHTTP.
50 "golang.org/x/net/context"
51 "golang.org/x/net/http2"
52 "google.golang.org/grpc/codes"
53 "google.golang.org/grpc/credentials"
54 "google.golang.org/grpc/metadata"
55 "google.golang.org/grpc/peer"
56 "google.golang.org/grpc/status"
59 // NewServerHandlerTransport returns a ServerTransport handling gRPC
60 // from inside an http.Handler. It requires that the http Server
62 func NewServerHandlerTransport(w http.ResponseWriter, r *http.Request) (ServerTransport, error) {
63 if r.ProtoMajor != 2 {
64 return nil, errors.New("gRPC requires HTTP/2")
66 if r.Method != "POST" {
67 return nil, errors.New("invalid gRPC request method")
69 if !validContentType(r.Header.Get("Content-Type")) {
70 return nil, errors.New("invalid gRPC request content-type")
72 if _, ok := w.(http.Flusher); !ok {
73 return nil, errors.New("gRPC requires a ResponseWriter supporting http.Flusher")
75 if _, ok := w.(http.CloseNotifier); !ok {
76 return nil, errors.New("gRPC requires a ResponseWriter supporting http.CloseNotifier")
79 st := &serverHandlerTransport{
82 closedCh: make(chan struct{}),
83 writes: make(chan func()),
86 if v := r.Header.Get("grpc-timeout"); v != "" {
87 to, err := decodeTimeout(v)
89 return nil, streamErrorf(codes.Internal, "malformed time-out: %v", err)
97 metakv = append(metakv, ":authority", r.Host)
99 for k, vv := range r.Header {
100 k = strings.ToLower(k)
101 if isReservedHeader(k) && !isWhitelistedPseudoHeader(k) {
104 for _, v := range vv {
105 if k == "user-agent" {
106 // user-agent is special. Copying logic of http_util.go.
107 if i := strings.LastIndex(v, " "); i == -1 {
108 // There is no application user agent string being set
114 v, err := decodeMetadataHeader(k, v)
116 return nil, streamErrorf(codes.InvalidArgument, "malformed binary metadata: %v", err)
118 metakv = append(metakv, k, v)
121 st.headerMD = metadata.Pairs(metakv...)
126 // serverHandlerTransport is an implementation of ServerTransport
127 // which replies to exactly one gRPC request (exactly one HTTP request),
128 // using the net/http.Handler interface. This http.Handler is guaranteed
129 // at this point to be speaking over HTTP/2, so it's able to speak valid
131 type serverHandlerTransport struct {
132 rw http.ResponseWriter
135 timeout time.Duration
136 didCommonHeaders bool
141 closedCh chan struct{} // closed on Close
143 // writes is a channel of code to run serialized in the
144 // ServeHTTP (HandleStreams) goroutine. The channel is closed
145 // when WriteStatus is called.
149 func (ht *serverHandlerTransport) Close() error {
150 ht.closeOnce.Do(ht.closeCloseChanOnce)
154 func (ht *serverHandlerTransport) closeCloseChanOnce() { close(ht.closedCh) }
156 func (ht *serverHandlerTransport) RemoteAddr() net.Addr { return strAddr(ht.req.RemoteAddr) }
158 // strAddr is a net.Addr backed by either a TCP "ip:port" string, or
159 // the empty string if unknown.
162 func (a strAddr) Network() string {
164 // Per the documentation on net/http.Request.RemoteAddr, if this is
165 // set, it's set to the IP:port of the peer (hence, TCP):
166 // https://golang.org/pkg/net/http/#Request
168 // If we want to support Unix sockets later, we can
169 // add our own grpc-specific convention within the
170 // grpc codebase to set RemoteAddr to a different
171 // format, or probably better: we can attach it to the
172 // context and use that from serverHandlerTransport.RemoteAddr.
178 func (a strAddr) String() string { return string(a) }
180 // do runs fn in the ServeHTTP goroutine.
181 func (ht *serverHandlerTransport) do(fn func()) error {
183 case ht.writes <- fn:
186 return ErrConnClosing
190 func (ht *serverHandlerTransport) WriteStatus(s *Stream, st *status.Status) error {
191 err := ht.do(func() {
192 ht.writeCommonHeaders(s)
194 // And flush, in case no header or body has been sent yet.
195 // This forces a separation of headers and trailers if this is the
196 // first call (for example, in end2end tests's TestNoService).
197 ht.rw.(http.Flusher).Flush()
200 h.Set("Grpc-Status", fmt.Sprintf("%d", st.Code()))
201 if m := st.Message(); m != "" {
202 h.Set("Grpc-Message", encodeGrpcMessage(m))
205 // TODO: Support Grpc-Status-Details-Bin
207 if md := s.Trailer(); len(md) > 0 {
208 for k, vv := range md {
209 // Clients don't tolerate reading restricted headers after some non restricted ones were sent.
210 if isReservedHeader(k) {
213 for _, v := range vv {
214 // http2 ResponseWriter mechanism to send undeclared Trailers after
215 // the headers have possibly been written.
216 h.Add(http2.TrailerPrefix+k, encodeMetadataHeader(k, v))
225 // writeCommonHeaders sets common headers on the first write
226 // call (Write, WriteHeader, or WriteStatus).
227 func (ht *serverHandlerTransport) writeCommonHeaders(s *Stream) {
228 if ht.didCommonHeaders {
231 ht.didCommonHeaders = true
234 h["Date"] = nil // suppress Date to make tests happy; TODO: restore
235 h.Set("Content-Type", "application/grpc")
237 // Predeclare trailers we'll set later in WriteStatus (after the body).
238 // This is a SHOULD in the HTTP RFC, and the way you add (known)
239 // Trailers per the net/http.ResponseWriter contract.
240 // See https://golang.org/pkg/net/http/#ResponseWriter
241 // and https://golang.org/pkg/net/http/#example_ResponseWriter_trailers
242 h.Add("Trailer", "Grpc-Status")
243 h.Add("Trailer", "Grpc-Message")
244 // TODO: Support Grpc-Status-Details-Bin
246 if s.sendCompress != "" {
247 h.Set("Grpc-Encoding", s.sendCompress)
251 func (ht *serverHandlerTransport) Write(s *Stream, data []byte, opts *Options) error {
252 return ht.do(func() {
253 ht.writeCommonHeaders(s)
256 ht.rw.(http.Flusher).Flush()
261 func (ht *serverHandlerTransport) WriteHeader(s *Stream, md metadata.MD) error {
262 return ht.do(func() {
263 ht.writeCommonHeaders(s)
265 for k, vv := range md {
266 // Clients don't tolerate reading restricted headers after some non restricted ones were sent.
267 if isReservedHeader(k) {
270 for _, v := range vv {
271 v = encodeMetadataHeader(k, v)
275 ht.rw.WriteHeader(200)
276 ht.rw.(http.Flusher).Flush()
280 func (ht *serverHandlerTransport) HandleStreams(startStream func(*Stream), traceCtx func(context.Context, string) context.Context) {
281 // With this transport type there will be exactly 1 stream: this HTTP request.
283 var ctx context.Context
284 var cancel context.CancelFunc
286 ctx, cancel = context.WithTimeout(context.Background(), ht.timeout)
288 ctx, cancel = context.WithCancel(context.Background())
291 // requestOver is closed when either the request's context is done
292 // or the status has been written via WriteStatus.
293 requestOver := make(chan struct{})
295 // clientGone receives a single value if peer is gone, either
296 // because the underlying connection is dead or because the
297 // peer sends an http2 RST_STREAM.
298 clientGone := ht.rw.(http.CloseNotifier).CloseNotify()
313 windowHandler: func(int) {}, // nothing
315 buf: newRecvBuffer(),
317 method: req.URL.Path,
318 recvCompress: req.Header.Get("grpc-encoding"),
321 Addr: ht.RemoteAddr(),
324 pr.AuthInfo = credentials.TLSInfo{State: *req.TLS}
326 ctx = metadata.NewIncomingContext(ctx, ht.headerMD)
327 ctx = peer.NewContext(ctx, pr)
328 s.ctx = newContextWithStream(ctx, s)
329 s.dec = &recvBufferReader{ctx: s.ctx, recv: s.buf}
331 // readerDone is closed when the Body.Read-ing goroutine exits.
332 readerDone := make(chan struct{})
334 defer close(readerDone)
336 // TODO: minimize garbage, optimize recvBuffer code/ownership
337 const readSize = 8196
338 for buf := make([]byte, readSize); ; {
339 n, err := req.Body.Read(buf)
341 s.buf.put(&recvMsg{data: buf[:n:n]})
345 s.buf.put(&recvMsg{err: mapRecvMsgError(err)})
349 buf = make([]byte, readSize)
354 // startStream is provided by the *grpc.Server's serveStreams.
355 // It starts a goroutine serving s and exits immediately.
356 // The goroutine that is started is the one that then calls
357 // into ht, calling WriteHeader, Write, WriteStatus, Close, etc.
363 // Wait for reading goroutine to finish.
368 func (ht *serverHandlerTransport) runStream() {
371 case fn, ok := <-ht.writes:
382 func (ht *serverHandlerTransport) Drain() {
383 panic("Drain() is not implemented")
386 // mapRecvMsgError returns the non-nil err into the appropriate
387 // error value as expected by callers of *grpc.parser.recvMsg.
388 // In particular, in can only be:
390 // * io.ErrUnexpectedEOF
391 // * of type transport.ConnectionError
392 // * of type transport.StreamError
393 func mapRecvMsgError(err error) error {
394 if err == io.EOF || err == io.ErrUnexpectedEOF {
397 if se, ok := err.(http2.StreamError); ok {
398 if code, ok := http2ErrConvTab[se.Code]; ok {
405 return connectionErrorf(true, err, err.Error())