google.golang.org/grpc@v1.62.1/internal/transport/handler_server.go (about) 1 /* 2 * 3 * Copyright 2016 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 // This file is the implementation of a gRPC server using HTTP/2 which 20 // uses the standard Go http2 Server implementation (via the 21 // http.Handler interface), rather than speaking low-level HTTP/2 22 // frames itself. It is the implementation of *grpc.Server.ServeHTTP. 23 24 package transport 25 26 import ( 27 "bytes" 28 "context" 29 "errors" 30 "fmt" 31 "io" 32 "net" 33 "net/http" 34 "strings" 35 "sync" 36 "time" 37 38 "golang.org/x/net/http2" 39 "google.golang.org/grpc/codes" 40 "google.golang.org/grpc/credentials" 41 "google.golang.org/grpc/internal/grpclog" 42 "google.golang.org/grpc/internal/grpcutil" 43 "google.golang.org/grpc/metadata" 44 "google.golang.org/grpc/peer" 45 "google.golang.org/grpc/stats" 46 "google.golang.org/grpc/status" 47 "google.golang.org/protobuf/proto" 48 ) 49 50 // NewServerHandlerTransport returns a ServerTransport handling gRPC from 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) (ServerTransport, error) { 54 if r.ProtoMajor != 2 { 55 msg := "gRPC requires HTTP/2" 56 http.Error(w, msg, http.StatusBadRequest) 57 return nil, errors.New(msg) 58 } 59 if r.Method != "POST" { 60 msg := fmt.Sprintf("invalid gRPC request method %q", r.Method) 61 http.Error(w, msg, http.StatusBadRequest) 62 return nil, errors.New(msg) 63 } 64 contentType := r.Header.Get("Content-Type") 65 // TODO: do we assume contentType is lowercase? we did before 66 contentSubtype, validContentType := grpcutil.ContentSubtype(contentType) 67 if !validContentType { 68 msg := fmt.Sprintf("invalid gRPC request content-type %q", contentType) 69 http.Error(w, msg, http.StatusUnsupportedMediaType) 70 return nil, errors.New(msg) 71 } 72 if _, ok := w.(http.Flusher); !ok { 73 msg := "gRPC requires a ResponseWriter supporting http.Flusher" 74 http.Error(w, msg, http.StatusInternalServerError) 75 return nil, errors.New(msg) 76 } 77 78 var localAddr net.Addr 79 if la := r.Context().Value(http.LocalAddrContextKey); la != nil { 80 localAddr, _ = la.(net.Addr) 81 } 82 var authInfo credentials.AuthInfo 83 if r.TLS != nil { 84 authInfo = credentials.TLSInfo{State: *r.TLS, CommonAuthInfo: credentials.CommonAuthInfo{SecurityLevel: credentials.PrivacyAndIntegrity}} 85 } 86 p := peer.Peer{ 87 Addr: strAddr(r.RemoteAddr), 88 LocalAddr: localAddr, 89 AuthInfo: authInfo, 90 } 91 st := &serverHandlerTransport{ 92 rw: w, 93 req: r, 94 closedCh: make(chan struct{}), 95 writes: make(chan func()), 96 peer: p, 97 contentType: contentType, 98 contentSubtype: contentSubtype, 99 stats: stats, 100 } 101 st.logger = prefixLoggerForServerHandlerTransport(st) 102 103 if v := r.Header.Get("grpc-timeout"); v != "" { 104 to, err := decodeTimeout(v) 105 if err != nil { 106 msg := fmt.Sprintf("malformed grpc-timeout: %v", err) 107 http.Error(w, msg, http.StatusBadRequest) 108 return nil, status.Error(codes.Internal, msg) 109 } 110 st.timeoutSet = true 111 st.timeout = to 112 } 113 114 metakv := []string{"content-type", contentType} 115 if r.Host != "" { 116 metakv = append(metakv, ":authority", r.Host) 117 } 118 for k, vv := range r.Header { 119 k = strings.ToLower(k) 120 if isReservedHeader(k) && !isWhitelistedHeader(k) { 121 continue 122 } 123 for _, v := range vv { 124 v, err := decodeMetadataHeader(k, v) 125 if err != nil { 126 msg := fmt.Sprintf("malformed binary metadata %q in header %q: %v", v, k, err) 127 http.Error(w, msg, http.StatusBadRequest) 128 return nil, status.Error(codes.Internal, msg) 129 } 130 metakv = append(metakv, k, v) 131 } 132 } 133 st.headerMD = metadata.Pairs(metakv...) 134 135 return st, nil 136 } 137 138 // serverHandlerTransport is an implementation of ServerTransport 139 // which replies to exactly one gRPC request (exactly one HTTP request), 140 // using the net/http.Handler interface. This http.Handler is guaranteed 141 // at this point to be speaking over HTTP/2, so it's able to speak valid 142 // gRPC. 143 type serverHandlerTransport struct { 144 rw http.ResponseWriter 145 req *http.Request 146 timeoutSet bool 147 timeout time.Duration 148 149 headerMD metadata.MD 150 151 peer peer.Peer 152 153 closeOnce sync.Once 154 closedCh chan struct{} // closed on Close 155 156 // writes is a channel of code to run serialized in the 157 // ServeHTTP (HandleStreams) goroutine. The channel is closed 158 // when WriteStatus is called. 159 writes chan func() 160 161 // block concurrent WriteStatus calls 162 // e.g. grpc/(*serverStream).SendMsg/RecvMsg 163 writeStatusMu sync.Mutex 164 165 // we just mirror the request content-type 166 contentType string 167 // we store both contentType and contentSubtype so we don't keep recreating them 168 // TODO make sure this is consistent across handler_server and http2_server 169 contentSubtype string 170 171 stats []stats.Handler 172 logger *grpclog.PrefixLogger 173 } 174 175 func (ht *serverHandlerTransport) Close(err error) { 176 ht.closeOnce.Do(func() { 177 if ht.logger.V(logLevel) { 178 ht.logger.Infof("Closing: %v", err) 179 } 180 close(ht.closedCh) 181 }) 182 } 183 184 func (ht *serverHandlerTransport) Peer() *peer.Peer { 185 return &peer.Peer{ 186 Addr: ht.peer.Addr, 187 LocalAddr: ht.peer.LocalAddr, 188 AuthInfo: ht.peer.AuthInfo, 189 } 190 } 191 192 // strAddr is a net.Addr backed by either a TCP "ip:port" string, or 193 // the empty string if unknown. 194 type strAddr string 195 196 func (a strAddr) Network() string { 197 if a != "" { 198 // Per the documentation on net/http.Request.RemoteAddr, if this is 199 // set, it's set to the IP:port of the peer (hence, TCP): 200 // https://golang.org/pkg/net/http/#Request 201 // 202 // If we want to support Unix sockets later, we can 203 // add our own grpc-specific convention within the 204 // grpc codebase to set RemoteAddr to a different 205 // format, or probably better: we can attach it to the 206 // context and use that from serverHandlerTransport.RemoteAddr. 207 return "tcp" 208 } 209 return "" 210 } 211 212 func (a strAddr) String() string { return string(a) } 213 214 // do runs fn in the ServeHTTP goroutine. 215 func (ht *serverHandlerTransport) do(fn func()) error { 216 select { 217 case <-ht.closedCh: 218 return ErrConnClosing 219 case ht.writes <- fn: 220 return nil 221 } 222 } 223 224 func (ht *serverHandlerTransport) WriteStatus(s *Stream, st *status.Status) error { 225 ht.writeStatusMu.Lock() 226 defer ht.writeStatusMu.Unlock() 227 228 headersWritten := s.updateHeaderSent() 229 err := ht.do(func() { 230 if !headersWritten { 231 ht.writePendingHeaders(s) 232 } 233 234 // And flush, in case no header or body has been sent yet. 235 // This forces a separation of headers and trailers if this is the 236 // first call (for example, in end2end tests's TestNoService). 237 ht.rw.(http.Flusher).Flush() 238 239 h := ht.rw.Header() 240 h.Set("Grpc-Status", fmt.Sprintf("%d", st.Code())) 241 if m := st.Message(); m != "" { 242 h.Set("Grpc-Message", encodeGrpcMessage(m)) 243 } 244 245 s.hdrMu.Lock() 246 if p := st.Proto(); p != nil && len(p.Details) > 0 { 247 delete(s.trailer, grpcStatusDetailsBinHeader) 248 stBytes, err := proto.Marshal(p) 249 if err != nil { 250 // TODO: return error instead, when callers are able to handle it. 251 panic(err) 252 } 253 254 h.Set(grpcStatusDetailsBinHeader, encodeBinHeader(stBytes)) 255 } 256 257 if len(s.trailer) > 0 { 258 for k, vv := range s.trailer { 259 // Clients don't tolerate reading restricted headers after some non restricted ones were sent. 260 if isReservedHeader(k) { 261 continue 262 } 263 for _, v := range vv { 264 // http2 ResponseWriter mechanism to send undeclared Trailers after 265 // the headers have possibly been written. 266 h.Add(http2.TrailerPrefix+k, encodeMetadataHeader(k, v)) 267 } 268 } 269 } 270 s.hdrMu.Unlock() 271 }) 272 273 if err == nil { // transport has not been closed 274 // Note: The trailer fields are compressed with hpack after this call returns. 275 // No WireLength field is set here. 276 for _, sh := range ht.stats { 277 sh.HandleRPC(s.Context(), &stats.OutTrailer{ 278 Trailer: s.trailer.Copy(), 279 }) 280 } 281 } 282 ht.Close(errors.New("finished writing status")) 283 return err 284 } 285 286 // writePendingHeaders sets common and custom headers on the first 287 // write call (Write, WriteHeader, or WriteStatus) 288 func (ht *serverHandlerTransport) writePendingHeaders(s *Stream) { 289 ht.writeCommonHeaders(s) 290 ht.writeCustomHeaders(s) 291 } 292 293 // writeCommonHeaders sets common headers on the first write 294 // call (Write, WriteHeader, or WriteStatus). 295 func (ht *serverHandlerTransport) writeCommonHeaders(s *Stream) { 296 h := ht.rw.Header() 297 h["Date"] = nil // suppress Date to make tests happy; TODO: restore 298 h.Set("Content-Type", ht.contentType) 299 300 // Predeclare trailers we'll set later in WriteStatus (after the body). 301 // This is a SHOULD in the HTTP RFC, and the way you add (known) 302 // Trailers per the net/http.ResponseWriter contract. 303 // See https://golang.org/pkg/net/http/#ResponseWriter 304 // and https://golang.org/pkg/net/http/#example_ResponseWriter_trailers 305 h.Add("Trailer", "Grpc-Status") 306 h.Add("Trailer", "Grpc-Message") 307 h.Add("Trailer", "Grpc-Status-Details-Bin") 308 309 if s.sendCompress != "" { 310 h.Set("Grpc-Encoding", s.sendCompress) 311 } 312 } 313 314 // writeCustomHeaders sets custom headers set on the stream via SetHeader 315 // on the first write call (Write, WriteHeader, or WriteStatus) 316 func (ht *serverHandlerTransport) writeCustomHeaders(s *Stream) { 317 h := ht.rw.Header() 318 319 s.hdrMu.Lock() 320 for k, vv := range s.header { 321 if isReservedHeader(k) { 322 continue 323 } 324 for _, v := range vv { 325 h.Add(k, encodeMetadataHeader(k, v)) 326 } 327 } 328 329 s.hdrMu.Unlock() 330 } 331 332 func (ht *serverHandlerTransport) Write(s *Stream, hdr []byte, data []byte, opts *Options) error { 333 headersWritten := s.updateHeaderSent() 334 return ht.do(func() { 335 if !headersWritten { 336 ht.writePendingHeaders(s) 337 } 338 ht.rw.Write(hdr) 339 ht.rw.Write(data) 340 ht.rw.(http.Flusher).Flush() 341 }) 342 } 343 344 func (ht *serverHandlerTransport) WriteHeader(s *Stream, md metadata.MD) error { 345 if err := s.SetHeader(md); err != nil { 346 return err 347 } 348 349 headersWritten := s.updateHeaderSent() 350 err := ht.do(func() { 351 if !headersWritten { 352 ht.writePendingHeaders(s) 353 } 354 355 ht.rw.WriteHeader(200) 356 ht.rw.(http.Flusher).Flush() 357 }) 358 359 if err == nil { 360 for _, sh := range ht.stats { 361 // Note: The header fields are compressed with hpack after this call returns. 362 // No WireLength field is set here. 363 sh.HandleRPC(s.Context(), &stats.OutHeader{ 364 Header: md.Copy(), 365 Compression: s.sendCompress, 366 }) 367 } 368 } 369 return err 370 } 371 372 func (ht *serverHandlerTransport) HandleStreams(ctx context.Context, startStream func(*Stream)) { 373 // With this transport type there will be exactly 1 stream: this HTTP request. 374 var cancel context.CancelFunc 375 if ht.timeoutSet { 376 ctx, cancel = context.WithTimeout(ctx, ht.timeout) 377 } else { 378 ctx, cancel = context.WithCancel(ctx) 379 } 380 381 // requestOver is closed when the status has been written via WriteStatus. 382 requestOver := make(chan struct{}) 383 go func() { 384 select { 385 case <-requestOver: 386 case <-ht.closedCh: 387 case <-ht.req.Context().Done(): 388 } 389 cancel() 390 ht.Close(errors.New("request is done processing")) 391 }() 392 393 ctx = metadata.NewIncomingContext(ctx, ht.headerMD) 394 req := ht.req 395 s := &Stream{ 396 id: 0, // irrelevant 397 ctx: ctx, 398 requestRead: func(int) {}, 399 cancel: cancel, 400 buf: newRecvBuffer(), 401 st: ht, 402 method: req.URL.Path, 403 recvCompress: req.Header.Get("grpc-encoding"), 404 contentSubtype: ht.contentSubtype, 405 headerWireLength: 0, // won't have access to header wire length until golang/go#18997. 406 } 407 s.trReader = &transportReader{ 408 reader: &recvBufferReader{ctx: s.ctx, ctxDone: s.ctx.Done(), recv: s.buf, freeBuffer: func(*bytes.Buffer) {}}, 409 windowHandler: func(int) {}, 410 } 411 412 // readerDone is closed when the Body.Read-ing goroutine exits. 413 readerDone := make(chan struct{}) 414 go func() { 415 defer close(readerDone) 416 417 // TODO: minimize garbage, optimize recvBuffer code/ownership 418 const readSize = 8196 419 for buf := make([]byte, readSize); ; { 420 n, err := req.Body.Read(buf) 421 if n > 0 { 422 s.buf.put(recvMsg{buffer: bytes.NewBuffer(buf[:n:n])}) 423 buf = buf[n:] 424 } 425 if err != nil { 426 s.buf.put(recvMsg{err: mapRecvMsgError(err)}) 427 return 428 } 429 if len(buf) == 0 { 430 buf = make([]byte, readSize) 431 } 432 } 433 }() 434 435 // startStream is provided by the *grpc.Server's serveStreams. 436 // It starts a goroutine serving s and exits immediately. 437 // The goroutine that is started is the one that then calls 438 // into ht, calling WriteHeader, Write, WriteStatus, Close, etc. 439 startStream(s) 440 441 ht.runStream() 442 close(requestOver) 443 444 // Wait for reading goroutine to finish. 445 req.Body.Close() 446 <-readerDone 447 } 448 449 func (ht *serverHandlerTransport) runStream() { 450 for { 451 select { 452 case fn := <-ht.writes: 453 fn() 454 case <-ht.closedCh: 455 return 456 } 457 } 458 } 459 460 func (ht *serverHandlerTransport) IncrMsgSent() {} 461 462 func (ht *serverHandlerTransport) IncrMsgRecv() {} 463 464 func (ht *serverHandlerTransport) Drain(debugData string) { 465 panic("Drain() is not implemented") 466 } 467 468 // mapRecvMsgError returns the non-nil err into the appropriate 469 // error value as expected by callers of *grpc.parser.recvMsg. 470 // In particular, in can only be: 471 // - io.EOF 472 // - io.ErrUnexpectedEOF 473 // - of type transport.ConnectionError 474 // - an error from the status package 475 func mapRecvMsgError(err error) error { 476 if err == io.EOF || err == io.ErrUnexpectedEOF { 477 return err 478 } 479 if se, ok := err.(http2.StreamError); ok { 480 if code, ok := http2ErrConvTab[se.Code]; ok { 481 return status.Error(code, se.Error()) 482 } 483 } 484 if strings.Contains(err.Error(), "body closed by handler") { 485 return status.Error(codes.Canceled, err.Error()) 486 } 487 return connectionErrorf(true, err, err.Error()) 488 }