3
* Copyright 2016 gRPC authors.
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
9
* http://www.apache.org/licenses/LICENSE-2.0
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.
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.
38
"github.com/golang/protobuf/proto"
39
"golang.org/x/net/http2"
40
"google.golang.org/grpc/codes"
41
"google.golang.org/grpc/credentials"
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"
49
// NewServerHandlerTransport returns a ServerTransport handling gRPC
50
// from inside an http.Handler. It requires that the http Server
52
func NewServerHandlerTransport(w http.ResponseWriter, r *http.Request, stats stats.Handler) (ServerTransport, error) {
53
if r.ProtoMajor != 2 {
54
return nil, errors.New("gRPC requires HTTP/2")
56
if r.Method != "POST" {
57
return nil, errors.New("invalid gRPC request method")
59
contentType := r.Header.Get("Content-Type")
60
// TODO: do we assume contentType is lowercase? we did before
61
contentSubtype, validContentType := grpcutil.ContentSubtype(contentType)
62
if !validContentType {
63
return nil, errors.New("invalid gRPC request content-type")
65
if _, ok := w.(http.Flusher); !ok {
66
return nil, errors.New("gRPC requires a ResponseWriter supporting http.Flusher")
69
st := &serverHandlerTransport{
72
closedCh: make(chan struct{}),
73
writes: make(chan func()),
74
contentType: contentType,
75
contentSubtype: contentSubtype,
79
if v := r.Header.Get("grpc-timeout"); v != "" {
80
to, err := decodeTimeout(v)
82
return nil, status.Errorf(codes.Internal, "malformed time-out: %v", err)
88
metakv := []string{"content-type", contentType}
90
metakv = append(metakv, ":authority", r.Host)
92
for k, vv := range r.Header {
93
k = strings.ToLower(k)
94
if isReservedHeader(k) && !isWhitelistedHeader(k) {
97
for _, v := range vv {
98
v, err := decodeMetadataHeader(k, v)
100
return nil, status.Errorf(codes.Internal, "malformed binary metadata: %v", err)
102
metakv = append(metakv, k, v)
105
st.headerMD = metadata.Pairs(metakv...)
110
// serverHandlerTransport is an implementation of ServerTransport
111
// which replies to exactly one gRPC request (exactly one HTTP request),
112
// using the net/http.Handler interface. This http.Handler is guaranteed
113
// at this point to be speaking over HTTP/2, so it's able to speak valid
115
type serverHandlerTransport struct {
116
rw http.ResponseWriter
119
timeout time.Duration
124
closedCh chan struct{} // closed on Close
126
// writes is a channel of code to run serialized in the
127
// ServeHTTP (HandleStreams) goroutine. The channel is closed
128
// when WriteStatus is called.
131
// block concurrent WriteStatus calls
132
// e.g. grpc/(*serverStream).SendMsg/RecvMsg
133
writeStatusMu sync.Mutex
135
// we just mirror the request content-type
137
// we store both contentType and contentSubtype so we don't keep recreating them
138
// TODO make sure this is consistent across handler_server and http2_server
139
contentSubtype string
144
func (ht *serverHandlerTransport) Close() error {
145
ht.closeOnce.Do(ht.closeCloseChanOnce)
149
func (ht *serverHandlerTransport) closeCloseChanOnce() { close(ht.closedCh) }
151
func (ht *serverHandlerTransport) RemoteAddr() net.Addr { return strAddr(ht.req.RemoteAddr) }
153
// strAddr is a net.Addr backed by either a TCP "ip:port" string, or
154
// the empty string if unknown.
157
func (a strAddr) Network() string {
159
// Per the documentation on net/http.Request.RemoteAddr, if this is
160
// set, it's set to the IP:port of the peer (hence, TCP):
161
// https://golang.org/pkg/net/http/#Request
163
// If we want to support Unix sockets later, we can
164
// add our own grpc-specific convention within the
165
// grpc codebase to set RemoteAddr to a different
166
// format, or probably better: we can attach it to the
167
// context and use that from serverHandlerTransport.RemoteAddr.
173
func (a strAddr) String() string { return string(a) }
175
// do runs fn in the ServeHTTP goroutine.
176
func (ht *serverHandlerTransport) do(fn func()) error {
179
return ErrConnClosing
180
case ht.writes <- fn:
185
func (ht *serverHandlerTransport) WriteStatus(s *Stream, st *status.Status) error {
186
ht.writeStatusMu.Lock()
187
defer ht.writeStatusMu.Unlock()
189
headersWritten := s.updateHeaderSent()
190
err := ht.do(func() {
192
ht.writePendingHeaders(s)
195
// And flush, in case no header or body has been sent yet.
196
// This forces a separation of headers and trailers if this is the
197
// first call (for example, in end2end tests's TestNoService).
198
ht.rw.(http.Flusher).Flush()
201
h.Set("Grpc-Status", fmt.Sprintf("%d", st.Code()))
202
if m := st.Message(); m != "" {
203
h.Set("Grpc-Message", encodeGrpcMessage(m))
206
if p := st.Proto(); p != nil && len(p.Details) > 0 {
207
stBytes, err := proto.Marshal(p)
209
// TODO: return error instead, when callers are able to handle it.
213
h.Set("Grpc-Status-Details-Bin", encodeBinHeader(stBytes))
216
if md := s.Trailer(); len(md) > 0 {
217
for k, vv := range md {
218
// Clients don't tolerate reading restricted headers after some non restricted ones were sent.
219
if isReservedHeader(k) {
222
for _, v := range vv {
223
// http2 ResponseWriter mechanism to send undeclared Trailers after
224
// the headers have possibly been written.
225
h.Add(http2.TrailerPrefix+k, encodeMetadataHeader(k, v))
231
if err == nil { // transport has not been closed
233
// Note: The trailer fields are compressed with hpack after this call returns.
234
// No WireLength field is set here.
235
ht.stats.HandleRPC(s.Context(), &stats.OutTrailer{
236
Trailer: s.trailer.Copy(),
244
// writePendingHeaders sets common and custom headers on the first
245
// write call (Write, WriteHeader, or WriteStatus)
246
func (ht *serverHandlerTransport) writePendingHeaders(s *Stream) {
247
ht.writeCommonHeaders(s)
248
ht.writeCustomHeaders(s)
251
// writeCommonHeaders sets common headers on the first write
252
// call (Write, WriteHeader, or WriteStatus).
253
func (ht *serverHandlerTransport) writeCommonHeaders(s *Stream) {
255
h["Date"] = nil // suppress Date to make tests happy; TODO: restore
256
h.Set("Content-Type", ht.contentType)
258
// Predeclare trailers we'll set later in WriteStatus (after the body).
259
// This is a SHOULD in the HTTP RFC, and the way you add (known)
260
// Trailers per the net/http.ResponseWriter contract.
261
// See https://golang.org/pkg/net/http/#ResponseWriter
262
// and https://golang.org/pkg/net/http/#example_ResponseWriter_trailers
263
h.Add("Trailer", "Grpc-Status")
264
h.Add("Trailer", "Grpc-Message")
265
h.Add("Trailer", "Grpc-Status-Details-Bin")
267
if s.sendCompress != "" {
268
h.Set("Grpc-Encoding", s.sendCompress)
272
// writeCustomHeaders sets custom headers set on the stream via SetHeader
273
// on the first write call (Write, WriteHeader, or WriteStatus).
274
func (ht *serverHandlerTransport) writeCustomHeaders(s *Stream) {
278
for k, vv := range s.header {
279
if isReservedHeader(k) {
282
for _, v := range vv {
283
h.Add(k, encodeMetadataHeader(k, v))
290
func (ht *serverHandlerTransport) Write(s *Stream, hdr []byte, data []byte, opts *Options) error {
291
headersWritten := s.updateHeaderSent()
292
return ht.do(func() {
294
ht.writePendingHeaders(s)
298
ht.rw.(http.Flusher).Flush()
302
func (ht *serverHandlerTransport) WriteHeader(s *Stream, md metadata.MD) error {
303
if err := s.SetHeader(md); err != nil {
307
headersWritten := s.updateHeaderSent()
308
err := ht.do(func() {
310
ht.writePendingHeaders(s)
313
ht.rw.WriteHeader(200)
314
ht.rw.(http.Flusher).Flush()
319
// Note: The header fields are compressed with hpack after this call returns.
320
// No WireLength field is set here.
321
ht.stats.HandleRPC(s.Context(), &stats.OutHeader{
323
Compression: s.sendCompress,
330
func (ht *serverHandlerTransport) HandleStreams(startStream func(*Stream), traceCtx func(context.Context, string) context.Context) {
331
// With this transport type there will be exactly 1 stream: this HTTP request.
333
ctx := ht.req.Context()
334
var cancel context.CancelFunc
336
ctx, cancel = context.WithTimeout(ctx, ht.timeout)
338
ctx, cancel = context.WithCancel(ctx)
341
// requestOver is closed when the status has been written via WriteStatus.
342
requestOver := make(chan struct{})
347
case <-ht.req.Context().Done():
357
requestRead: func(int) {},
359
buf: newRecvBuffer(),
361
method: req.URL.Path,
362
recvCompress: req.Header.Get("grpc-encoding"),
363
contentSubtype: ht.contentSubtype,
366
Addr: ht.RemoteAddr(),
369
pr.AuthInfo = credentials.TLSInfo{State: *req.TLS, CommonAuthInfo: credentials.CommonAuthInfo{SecurityLevel: credentials.PrivacyAndIntegrity}}
371
ctx = metadata.NewIncomingContext(ctx, ht.headerMD)
372
s.ctx = peer.NewContext(ctx, pr)
374
s.ctx = ht.stats.TagRPC(s.ctx, &stats.RPCTagInfo{FullMethodName: s.method})
375
inHeader := &stats.InHeader{
376
FullMethod: s.method,
377
RemoteAddr: ht.RemoteAddr(),
378
Compression: s.recvCompress,
380
ht.stats.HandleRPC(s.ctx, inHeader)
382
s.trReader = &transportReader{
383
reader: &recvBufferReader{ctx: s.ctx, ctxDone: s.ctx.Done(), recv: s.buf, freeBuffer: func(*bytes.Buffer) {}},
384
windowHandler: func(int) {},
387
// readerDone is closed when the Body.Read-ing goroutine exits.
388
readerDone := make(chan struct{})
390
defer close(readerDone)
392
// TODO: minimize garbage, optimize recvBuffer code/ownership
393
const readSize = 8196
394
for buf := make([]byte, readSize); ; {
395
n, err := req.Body.Read(buf)
397
s.buf.put(recvMsg{buffer: bytes.NewBuffer(buf[:n:n])})
401
s.buf.put(recvMsg{err: mapRecvMsgError(err)})
405
buf = make([]byte, readSize)
410
// startStream is provided by the *grpc.Server's serveStreams.
411
// It starts a goroutine serving s and exits immediately.
412
// The goroutine that is started is the one that then calls
413
// into ht, calling WriteHeader, Write, WriteStatus, Close, etc.
419
// Wait for reading goroutine to finish.
424
func (ht *serverHandlerTransport) runStream() {
427
case fn := <-ht.writes:
435
func (ht *serverHandlerTransport) IncrMsgSent() {}
437
func (ht *serverHandlerTransport) IncrMsgRecv() {}
439
func (ht *serverHandlerTransport) Drain() {
440
panic("Drain() is not implemented")
443
// mapRecvMsgError returns the non-nil err into the appropriate
444
// error value as expected by callers of *grpc.parser.recvMsg.
445
// In particular, in can only be:
447
// * io.ErrUnexpectedEOF
448
// * of type transport.ConnectionError
449
// * an error from the status package
450
func mapRecvMsgError(err error) error {
451
if err == io.EOF || err == io.ErrUnexpectedEOF {
454
if se, ok := err.(http2.StreamError); ok {
455
if code, ok := http2ErrConvTab[se.Code]; ok {
456
return status.Error(code, se.Error())
459
if strings.Contains(err.Error(), "body closed by handler") {
460
return status.Error(codes.Canceled, err.Error())
462
return connectionErrorf(true, err, err.Error())