encoding.go (5169B)
1 /* 2 * 3 * Copyright 2017 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 // Package encoding defines the interface for the compressor and codec, and 20 // functions to register and retrieve compressors and codecs. 21 // 22 // # Experimental 23 // 24 // Notice: This package is EXPERIMENTAL and may be changed or removed in a 25 // later release. 26 package encoding 27 28 import ( 29 "io" 30 "strings" 31 32 "google.golang.org/grpc/internal/grpcutil" 33 ) 34 35 // Identity specifies the optional encoding for uncompressed streams. 36 // It is intended for grpc internal use only. 37 const Identity = "identity" 38 39 // Compressor is used for compressing and decompressing when sending or 40 // receiving messages. 41 type Compressor interface { 42 // Compress writes the data written to wc to w after compressing it. If an 43 // error occurs while initializing the compressor, that error is returned 44 // instead. 45 Compress(w io.Writer) (io.WriteCloser, error) 46 // Decompress reads data from r, decompresses it, and provides the 47 // uncompressed data via the returned io.Reader. If an error occurs while 48 // initializing the decompressor, that error is returned instead. 49 Decompress(r io.Reader) (io.Reader, error) 50 // Name is the name of the compression codec and is used to set the content 51 // coding header. The result must be static; the result cannot change 52 // between calls. 53 Name() string 54 // If a Compressor implements 55 // DecompressedSize(compressedBytes []byte) int, gRPC will call it 56 // to determine the size of the buffer allocated for the result of decompression. 57 // Return -1 to indicate unknown size. 58 // 59 // Experimental 60 // 61 // Notice: This API is EXPERIMENTAL and may be changed or removed in a 62 // later release. 63 } 64 65 var registeredCompressor = make(map[string]Compressor) 66 67 // RegisterCompressor registers the compressor with gRPC by its name. It can 68 // be activated when sending an RPC via grpc.UseCompressor(). It will be 69 // automatically accessed when receiving a message based on the content coding 70 // header. Servers also use it to send a response with the same encoding as 71 // the request. 72 // 73 // NOTE: this function must only be called during initialization time (i.e. in 74 // an init() function), and is not thread-safe. If multiple Compressors are 75 // registered with the same name, the one registered last will take effect. 76 func RegisterCompressor(c Compressor) { 77 registeredCompressor[c.Name()] = c 78 if !grpcutil.IsCompressorNameRegistered(c.Name()) { 79 grpcutil.RegisteredCompressorNames = append(grpcutil.RegisteredCompressorNames, c.Name()) 80 } 81 } 82 83 // GetCompressor returns Compressor for the given compressor name. 84 func GetCompressor(name string) Compressor { 85 return registeredCompressor[name] 86 } 87 88 // Codec defines the interface gRPC uses to encode and decode messages. Note 89 // that implementations of this interface must be thread safe; a Codec's 90 // methods can be called from concurrent goroutines. 91 type Codec interface { 92 // Marshal returns the wire format of v. 93 Marshal(v interface{}) ([]byte, error) 94 // Unmarshal parses the wire format into v. 95 Unmarshal(data []byte, v interface{}) error 96 // Name returns the name of the Codec implementation. The returned string 97 // will be used as part of content type in transmission. The result must be 98 // static; the result cannot change between calls. 99 Name() string 100 } 101 102 var registeredCodecs = make(map[string]Codec) 103 104 // RegisterCodec registers the provided Codec for use with all gRPC clients and 105 // servers. 106 // 107 // The Codec will be stored and looked up by result of its Name() method, which 108 // should match the content-subtype of the encoding handled by the Codec. This 109 // is case-insensitive, and is stored and looked up as lowercase. If the 110 // result of calling Name() is an empty string, RegisterCodec will panic. See 111 // Content-Type on 112 // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for 113 // more details. 114 // 115 // NOTE: this function must only be called during initialization time (i.e. in 116 // an init() function), and is not thread-safe. If multiple Codecs are 117 // registered with the same name, the one registered last will take effect. 118 func RegisterCodec(codec Codec) { 119 if codec == nil { 120 panic("cannot register a nil Codec") 121 } 122 if codec.Name() == "" { 123 panic("cannot register Codec with empty string result for Name()") 124 } 125 contentSubtype := strings.ToLower(codec.Name()) 126 registeredCodecs[contentSubtype] = codec 127 } 128 129 // GetCodec gets a registered Codec by content-subtype, or nil if no Codec is 130 // registered for the content-subtype. 131 // 132 // The content-subtype is expected to be lowercase. 133 func GetCodec(contentSubtype string) Codec { 134 return registeredCodecs[contentSubtype] 135 }