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