...
1 package runtime
2
3 import (
4 "context"
5 "io"
6 "net/http"
7
8 "github.com/golang/protobuf/ptypes/any"
9 "github.com/grpc-ecosystem/grpc-gateway/internal"
10 "google.golang.org/grpc/codes"
11 "google.golang.org/grpc/grpclog"
12 "google.golang.org/grpc/status"
13 )
14
15
16
17 type StreamErrorHandlerFunc func(context.Context, error) *StreamError
18
19
20
21 type StreamError internal.StreamError
22
23
24 type ProtoErrorHandlerFunc func(context.Context, *ServeMux, Marshaler, http.ResponseWriter, *http.Request, error)
25
26 var _ ProtoErrorHandlerFunc = DefaultHTTPProtoErrorHandler
27
28
29
30
31
32
33
34
35 func DefaultHTTPProtoErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, _ *http.Request, err error) {
36
37 const fallback = `{"code": 13, "message": "failed to marshal error message"}`
38
39 s, ok := status.FromError(err)
40 if !ok {
41 s = status.New(codes.Unknown, err.Error())
42 }
43
44 w.Header().Del("Trailer")
45
46 contentType := marshaler.ContentType()
47
48
49
50 if typeMarshaler, ok := marshaler.(contentTypeMarshaler); ok {
51 pb := s.Proto()
52 contentType = typeMarshaler.ContentTypeFromMessage(pb)
53 }
54 w.Header().Set("Content-Type", contentType)
55
56 buf, merr := marshaler.Marshal(s.Proto())
57 if merr != nil {
58 grpclog.Infof("Failed to marshal error message %q: %v", s.Proto(), merr)
59 w.WriteHeader(http.StatusInternalServerError)
60 if _, err := io.WriteString(w, fallback); err != nil {
61 grpclog.Infof("Failed to write response: %v", err)
62 }
63 return
64 }
65
66 md, ok := ServerMetadataFromContext(ctx)
67 if !ok {
68 grpclog.Infof("Failed to extract ServerMetadata from context")
69 }
70
71 handleForwardResponseServerMetadata(w, mux, md)
72 handleForwardResponseTrailerHeader(w, md)
73 st := HTTPStatusFromCode(s.Code())
74 w.WriteHeader(st)
75 if _, err := w.Write(buf); err != nil {
76 grpclog.Infof("Failed to write response: %v", err)
77 }
78
79 handleForwardResponseTrailer(w, md)
80 }
81
82
83
84
85
86
87
88
89 func DefaultHTTPStreamErrorHandler(_ context.Context, err error) *StreamError {
90 grpcCode := codes.Unknown
91 grpcMessage := err.Error()
92 var grpcDetails []*any.Any
93 if s, ok := status.FromError(err); ok {
94 grpcCode = s.Code()
95 grpcMessage = s.Message()
96 grpcDetails = s.Proto().GetDetails()
97 }
98 httpCode := HTTPStatusFromCode(grpcCode)
99 return &StreamError{
100 GrpcCode: int32(grpcCode),
101 HttpCode: int32(httpCode),
102 Message: grpcMessage,
103 HttpStatus: http.StatusText(httpCode),
104 Details: grpcDetails,
105 }
106 }
107
View as plain text