gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

marshaler_registry.go (3190B)


      1 package runtime
      2 
      3 import (
      4 	"errors"
      5 	"mime"
      6 	"net/http"
      7 
      8 	"google.golang.org/grpc/grpclog"
      9 	"google.golang.org/protobuf/encoding/protojson"
     10 )
     11 
     12 // MIMEWildcard is the fallback MIME type used for requests which do not match
     13 // a registered MIME type.
     14 const MIMEWildcard = "*"
     15 
     16 var (
     17 	acceptHeader      = http.CanonicalHeaderKey("Accept")
     18 	contentTypeHeader = http.CanonicalHeaderKey("Content-Type")
     19 
     20 	defaultMarshaler = &HTTPBodyMarshaler{
     21 		Marshaler: &JSONPb{
     22 			MarshalOptions: protojson.MarshalOptions{
     23 				EmitUnpopulated: true,
     24 			},
     25 			UnmarshalOptions: protojson.UnmarshalOptions{
     26 				DiscardUnknown: true,
     27 			},
     28 		},
     29 	}
     30 )
     31 
     32 // MarshalerForRequest returns the inbound/outbound marshalers for this request.
     33 // It checks the registry on the ServeMux for the MIME type set by the Content-Type header.
     34 // If it isn't set (or the request Content-Type is empty), checks for "*".
     35 // If there are multiple Content-Type headers set, choose the first one that it can
     36 // exactly match in the registry.
     37 // Otherwise, it follows the above logic for "*"/InboundMarshaler/OutboundMarshaler.
     38 func MarshalerForRequest(mux *ServeMux, r *http.Request) (inbound Marshaler, outbound Marshaler) {
     39 	for _, acceptVal := range r.Header[acceptHeader] {
     40 		if m, ok := mux.marshalers.mimeMap[acceptVal]; ok {
     41 			outbound = m
     42 			break
     43 		}
     44 	}
     45 
     46 	for _, contentTypeVal := range r.Header[contentTypeHeader] {
     47 		contentType, _, err := mime.ParseMediaType(contentTypeVal)
     48 		if err != nil {
     49 			grpclog.Infof("Failed to parse Content-Type %s: %v", contentTypeVal, err)
     50 			continue
     51 		}
     52 		if m, ok := mux.marshalers.mimeMap[contentType]; ok {
     53 			inbound = m
     54 			break
     55 		}
     56 	}
     57 
     58 	if inbound == nil {
     59 		inbound = mux.marshalers.mimeMap[MIMEWildcard]
     60 	}
     61 	if outbound == nil {
     62 		outbound = inbound
     63 	}
     64 
     65 	return inbound, outbound
     66 }
     67 
     68 // marshalerRegistry is a mapping from MIME types to Marshalers.
     69 type marshalerRegistry struct {
     70 	mimeMap map[string]Marshaler
     71 }
     72 
     73 // add adds a marshaler for a case-sensitive MIME type string ("*" to match any
     74 // MIME type).
     75 func (m marshalerRegistry) add(mime string, marshaler Marshaler) error {
     76 	if len(mime) == 0 {
     77 		return errors.New("empty MIME type")
     78 	}
     79 
     80 	m.mimeMap[mime] = marshaler
     81 
     82 	return nil
     83 }
     84 
     85 // makeMarshalerMIMERegistry returns a new registry of marshalers.
     86 // It allows for a mapping of case-sensitive Content-Type MIME type string to runtime.Marshaler interfaces.
     87 //
     88 // For example, you could allow the client to specify the use of the runtime.JSONPb marshaler
     89 // with a "application/jsonpb" Content-Type and the use of the runtime.JSONBuiltin marshaler
     90 // with a "application/json" Content-Type.
     91 // "*" can be used to match any Content-Type.
     92 // This can be attached to a ServerMux with the marshaler option.
     93 func makeMarshalerMIMERegistry() marshalerRegistry {
     94 	return marshalerRegistry{
     95 		mimeMap: map[string]Marshaler{
     96 			MIMEWildcard: defaultMarshaler,
     97 		},
     98 	}
     99 }
    100 
    101 // WithMarshalerOption returns a ServeMuxOption which associates inbound and outbound
    102 // Marshalers to a MIME type in mux.
    103 func WithMarshalerOption(mime string, marshaler Marshaler) ServeMuxOption {
    104 	return func(mux *ServeMux) {
    105 		if err := mux.marshalers.add(mime, marshaler); err != nil {
    106 			panic(err)
    107 		}
    108 	}
    109 }