]>
Commit | Line | Data |
---|---|---|
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. | |
23 | package encoding | |
24 | ||
25 | import ( | |
26 | "io" | |
27 | "strings" | |
28 | ) | |
29 | ||
30 | // Identity specifies the optional encoding for uncompressed streams. | |
31 | // It is intended for grpc internal use only. | |
32 | const Identity = "identity" | |
33 | ||
34 | // Compressor is used for compressing and decompressing when sending or | |
35 | // receiving messages. | |
36 | type 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 | ||
51 | var 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. | |
62 | func RegisterCompressor(c Compressor) { | |
63 | registeredCompressor[c.Name()] = c | |
64 | } | |
65 | ||
66 | // GetCompressor returns Compressor for the given compressor name. | |
67 | func 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. | |
74 | type 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 | ||
85 | var 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. | |
101 | func 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. | |
116 | func GetCodec(contentSubtype string) Codec { | |
117 | return registeredCodecs[contentSubtype] | |
118 | } |