mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 13:50:01 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			147 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package runtime
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"io"
 | |
| 	"net/http"
 | |
| 
 | |
| 	"github.com/golang/protobuf/proto"
 | |
| 	"github.com/golang/protobuf/ptypes/any"
 | |
| 	"google.golang.org/grpc/codes"
 | |
| 	"google.golang.org/grpc/grpclog"
 | |
| 	"google.golang.org/grpc/status"
 | |
| )
 | |
| 
 | |
| // HTTPStatusFromCode converts a gRPC error code into the corresponding HTTP response status.
 | |
| // See: https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto
 | |
| func HTTPStatusFromCode(code codes.Code) int {
 | |
| 	switch code {
 | |
| 	case codes.OK:
 | |
| 		return http.StatusOK
 | |
| 	case codes.Canceled:
 | |
| 		return http.StatusRequestTimeout
 | |
| 	case codes.Unknown:
 | |
| 		return http.StatusInternalServerError
 | |
| 	case codes.InvalidArgument:
 | |
| 		return http.StatusBadRequest
 | |
| 	case codes.DeadlineExceeded:
 | |
| 		return http.StatusGatewayTimeout
 | |
| 	case codes.NotFound:
 | |
| 		return http.StatusNotFound
 | |
| 	case codes.AlreadyExists:
 | |
| 		return http.StatusConflict
 | |
| 	case codes.PermissionDenied:
 | |
| 		return http.StatusForbidden
 | |
| 	case codes.Unauthenticated:
 | |
| 		return http.StatusUnauthorized
 | |
| 	case codes.ResourceExhausted:
 | |
| 		return http.StatusTooManyRequests
 | |
| 	case codes.FailedPrecondition:
 | |
| 		// Note, this deliberately doesn't translate to the similarly named '412 Precondition Failed' HTTP response status.
 | |
| 		return http.StatusBadRequest
 | |
| 	case codes.Aborted:
 | |
| 		return http.StatusConflict
 | |
| 	case codes.OutOfRange:
 | |
| 		return http.StatusBadRequest
 | |
| 	case codes.Unimplemented:
 | |
| 		return http.StatusNotImplemented
 | |
| 	case codes.Internal:
 | |
| 		return http.StatusInternalServerError
 | |
| 	case codes.Unavailable:
 | |
| 		return http.StatusServiceUnavailable
 | |
| 	case codes.DataLoss:
 | |
| 		return http.StatusInternalServerError
 | |
| 	}
 | |
| 
 | |
| 	grpclog.Infof("Unknown gRPC error code: %v", code)
 | |
| 	return http.StatusInternalServerError
 | |
| }
 | |
| 
 | |
| var (
 | |
| 	// HTTPError replies to the request with the error.
 | |
| 	// You can set a custom function to this variable to customize error format.
 | |
| 	HTTPError = DefaultHTTPError
 | |
| 	// OtherErrorHandler handles the following error used by the gateway: StatusMethodNotAllowed StatusNotFound and StatusBadRequest
 | |
| 	OtherErrorHandler = DefaultOtherErrorHandler
 | |
| )
 | |
| 
 | |
| type errorBody struct {
 | |
| 	Error string `protobuf:"bytes,1,name=error" json:"error"`
 | |
| 	// This is to make the error more compatible with users that expect errors to be Status objects:
 | |
| 	// https://github.com/grpc/grpc/blob/master/src/proto/grpc/status/status.proto
 | |
| 	// It should be the exact same message as the Error field.
 | |
| 	Message string     `protobuf:"bytes,1,name=message" json:"message"`
 | |
| 	Code    int32      `protobuf:"varint,2,name=code" json:"code"`
 | |
| 	Details []*any.Any `protobuf:"bytes,3,rep,name=details" json:"details,omitempty"`
 | |
| }
 | |
| 
 | |
| // Make this also conform to proto.Message for builtin JSONPb Marshaler
 | |
| func (e *errorBody) Reset()         { *e = errorBody{} }
 | |
| func (e *errorBody) String() string { return proto.CompactTextString(e) }
 | |
| func (*errorBody) ProtoMessage()    {}
 | |
| 
 | |
| // DefaultHTTPError is the default implementation of HTTPError.
 | |
| // If "err" is an error from gRPC system, the function replies with the status code mapped by HTTPStatusFromCode.
 | |
| // If otherwise, it replies with http.StatusInternalServerError.
 | |
| //
 | |
| // The response body returned by this function is a JSON object,
 | |
| // which contains a member whose key is "error" and whose value is err.Error().
 | |
| func DefaultHTTPError(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, _ *http.Request, err error) {
 | |
| 	const fallback = `{"error": "failed to marshal error message"}`
 | |
| 
 | |
| 	s, ok := status.FromError(err)
 | |
| 	if !ok {
 | |
| 		s = status.New(codes.Unknown, err.Error())
 | |
| 	}
 | |
| 
 | |
| 	w.Header().Del("Trailer")
 | |
| 
 | |
| 	contentType := marshaler.ContentType()
 | |
| 	// Check marshaler on run time in order to keep backwards compatability
 | |
| 	// An interface param needs to be added to the ContentType() function on
 | |
| 	// the Marshal interface to be able to remove this check
 | |
| 	if httpBodyMarshaler, ok := marshaler.(*HTTPBodyMarshaler); ok {
 | |
| 		pb := s.Proto()
 | |
| 		contentType = httpBodyMarshaler.ContentTypeFromMessage(pb)
 | |
| 	}
 | |
| 	w.Header().Set("Content-Type", contentType)
 | |
| 
 | |
| 	body := &errorBody{
 | |
| 		Error:   s.Message(),
 | |
| 		Message: s.Message(),
 | |
| 		Code:    int32(s.Code()),
 | |
| 		Details: s.Proto().GetDetails(),
 | |
| 	}
 | |
| 
 | |
| 	buf, merr := marshaler.Marshal(body)
 | |
| 	if merr != nil {
 | |
| 		grpclog.Infof("Failed to marshal error message %q: %v", body, merr)
 | |
| 		w.WriteHeader(http.StatusInternalServerError)
 | |
| 		if _, err := io.WriteString(w, fallback); err != nil {
 | |
| 			grpclog.Infof("Failed to write response: %v", err)
 | |
| 		}
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	md, ok := ServerMetadataFromContext(ctx)
 | |
| 	if !ok {
 | |
| 		grpclog.Infof("Failed to extract ServerMetadata from context")
 | |
| 	}
 | |
| 
 | |
| 	handleForwardResponseServerMetadata(w, mux, md)
 | |
| 	handleForwardResponseTrailerHeader(w, md)
 | |
| 	st := HTTPStatusFromCode(s.Code())
 | |
| 	w.WriteHeader(st)
 | |
| 	if _, err := w.Write(buf); err != nil {
 | |
| 		grpclog.Infof("Failed to write response: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	handleForwardResponseTrailer(w, md)
 | |
| }
 | |
| 
 | |
| // DefaultOtherErrorHandler is the default implementation of OtherErrorHandler.
 | |
| // It simply writes a string representation of the given error into "w".
 | |
| func DefaultOtherErrorHandler(w http.ResponseWriter, _ *http.Request, msg string, code int) {
 | |
| 	http.Error(w, msg, code)
 | |
| }
 |