/*
 *
 * Copyright 2014 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

// Package metadata define the structure of the metadata supported by gRPC library. // Please refer to https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md // for more information about custom-metadata.
package metadata // import "google.golang.org/grpc/metadata" import ( ) // DecodeKeyValue returns k, v, nil. // // Deprecated: use k and v directly instead. func (, string) (string, string, error) { return , , nil } // MD is a mapping from metadata keys to values. Users should use the following // two convenience functions New and Pairs to generate MD. type MD map[string][]string // New creates an MD from a given key-value map. // // Only the following ASCII characters are allowed in keys: // - digits: 0-9 // - uppercase letters: A-Z (normalized to lower) // - lowercase letters: a-z // - special characters: -_. // // Uppercase letters are automatically converted to lowercase. // // Keys beginning with "grpc-" are reserved for grpc-internal use only and may // result in errors if set in metadata. func ( map[string]string) MD { := make(MD, len()) for , := range { := strings.ToLower() [] = append([], ) } return } // Pairs returns an MD formed by the mapping of key, value ... // Pairs panics if len(kv) is odd. // // Only the following ASCII characters are allowed in keys: // - digits: 0-9 // - uppercase letters: A-Z (normalized to lower) // - lowercase letters: a-z // - special characters: -_. // // Uppercase letters are automatically converted to lowercase. // // Keys beginning with "grpc-" are reserved for grpc-internal use only and may // result in errors if set in metadata. func ( ...string) MD { if len()%2 == 1 { panic(fmt.Sprintf("metadata: Pairs got the odd number of input pairs for metadata: %d", len())) } := make(MD, len()/2) for := 0; < len(); += 2 { := strings.ToLower([]) [] = append([], [+1]) } return } // Len returns the number of items in md. func ( MD) () int { return len() } // Copy returns a copy of md. func ( MD) () MD { return Join() } // Get obtains the values for a given key. // // k is converted to lowercase before searching in md. func ( MD) ( string) []string { = strings.ToLower() return [] } // Set sets the value of a given key with a slice of values. // // k is converted to lowercase before storing in md. func ( MD) ( string, ...string) { if len() == 0 { return } = strings.ToLower() [] = } // Append adds the values to key k, not overwriting what was already stored at // that key. // // k is converted to lowercase before storing in md. func ( MD) ( string, ...string) { if len() == 0 { return } = strings.ToLower() [] = append([], ...) } // Delete removes the values for a given key k which is converted to lowercase // before removing it from md. func ( MD) ( string) { = strings.ToLower() delete(, ) } // Join joins any number of mds into a single MD. // // The order of values for each key is determined by the order in which the mds // containing those values are presented to Join. func ( ...MD) MD { := MD{} for , := range { for , := range { [] = append([], ...) } } return } type mdIncomingKey struct{} type mdOutgoingKey struct{} // NewIncomingContext creates a new context with incoming md attached. func ( context.Context, MD) context.Context { return context.WithValue(, mdIncomingKey{}, ) } // NewOutgoingContext creates a new context with outgoing md attached. If used // in conjunction with AppendToOutgoingContext, NewOutgoingContext will // overwrite any previously-appended metadata. func ( context.Context, MD) context.Context { return context.WithValue(, mdOutgoingKey{}, rawMD{md: }) } // AppendToOutgoingContext returns a new context with the provided kv merged // with any existing metadata in the context. Please refer to the documentation // of Pairs for a description of kv. func ( context.Context, ...string) context.Context { if len()%2 == 1 { panic(fmt.Sprintf("metadata: AppendToOutgoingContext got an odd number of input pairs for metadata: %d", len())) } , := .Value(mdOutgoingKey{}).(rawMD) := make([][]string, len(.added)+1) copy(, .added) [len()-1] = make([]string, len()) copy([len()-1], ) return context.WithValue(, mdOutgoingKey{}, rawMD{md: .md, added: }) } // FromIncomingContext returns the incoming metadata in ctx if it exists. // // All keys in the returned MD are lowercase. func ( context.Context) (MD, bool) { , := .Value(mdIncomingKey{}).(MD) if ! { return nil, false } := make(MD, len()) for , := range { // We need to manually convert all keys to lower case, because MD is a // map, and there's no guarantee that the MD attached to the context is // created using our helper functions. := strings.ToLower() [] = copyOf() } return , true } // ValueFromIncomingContext returns the metadata value corresponding to the metadata // key from the incoming metadata if it exists. Key must be lower-case. // // # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. func ( context.Context, string) []string { , := .Value(mdIncomingKey{}).(MD) if ! { return nil } if , := []; { return copyOf() } for , := range { // We need to manually convert all keys to lower case, because MD is a // map, and there's no guarantee that the MD attached to the context is // created using our helper functions. if strings.ToLower() == { return copyOf() } } return nil } // the returned slice must not be modified in place func ( []string) []string { := make([]string, len()) copy(, ) return } // FromOutgoingContextRaw returns the un-merged, intermediary contents of rawMD. // // Remember to perform strings.ToLower on the keys, for both the returned MD (MD // is a map, there's no guarantee it's created using our helper functions) and // the extra kv pairs (AppendToOutgoingContext doesn't turn them into // lowercase). // // This is intended for gRPC-internal use ONLY. Users should use // FromOutgoingContext instead. func ( context.Context) (MD, [][]string, bool) { , := .Value(mdOutgoingKey{}).(rawMD) if ! { return nil, nil, false } return .md, .added, true } // FromOutgoingContext returns the outgoing metadata in ctx if it exists. // // All keys in the returned MD are lowercase. func ( context.Context) (MD, bool) { , := .Value(mdOutgoingKey{}).(rawMD) if ! { return nil, false } := len(.md) for := range .added { += len(.added[]) / 2 } := make(MD, ) for , := range .md { // We need to manually convert all keys to lower case, because MD is a // map, and there's no guarantee that the MD attached to the context is // created using our helper functions. := strings.ToLower() [] = copyOf() } for , := range .added { if len()%2 == 1 { panic(fmt.Sprintf("metadata: FromOutgoingContext got an odd number of input pairs for metadata: %d", len())) } for := 0; < len(); += 2 { := strings.ToLower([]) [] = append([], [+1]) } } return , } type rawMD struct { md MD added [][]string }