fix metadata issues with uppercase letters
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
		| @@ -3,7 +3,7 @@ package metadata | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"strings" | 	"net/textproto" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type metadataKey struct{} | type metadataKey struct{} | ||||||
| @@ -14,53 +14,48 @@ type metadataKey struct{} | |||||||
| type Metadata map[string]string | type Metadata map[string]string | ||||||
|  |  | ||||||
| func (md Metadata) Get(key string) (string, bool) { | func (md Metadata) Get(key string) (string, bool) { | ||||||
| 	// attempt to get as is | 	// fast path | ||||||
| 	val, ok := md[key] | 	val, ok := md[key] | ||||||
| 	if ok { | 	if !ok { | ||||||
| 		return val, ok | 		// slow path | ||||||
|  | 		val, ok = md[textproto.CanonicalMIMEHeaderKey(key)] | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// attempt to get lower case |  | ||||||
| 	val, ok = md[strings.Title(key)] |  | ||||||
| 	return val, ok | 	return val, ok | ||||||
| } | } | ||||||
|  |  | ||||||
| func (md Metadata) Set(key, val string) { | func (md Metadata) Set(key, val string) { | ||||||
| 	md[key] = val | 	md[textproto.CanonicalMIMEHeaderKey(key)] = val | ||||||
| } | } | ||||||
|  |  | ||||||
| func (md Metadata) Delete(key string) { | func (md Metadata) Del(key string) { | ||||||
| 	// delete key as-is | 	delete(md, textproto.CanonicalMIMEHeaderKey(key)) | ||||||
| 	delete(md, key) |  | ||||||
| 	// delete also Title key |  | ||||||
| 	delete(md, strings.Title(key)) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // Copy makes a copy of the metadata | // Copy makes a copy of the metadata | ||||||
| func Copy(md Metadata) Metadata { | func Copy(md Metadata) Metadata { | ||||||
| 	cmd := make(Metadata, len(md)) | 	nmd := make(Metadata, len(md)) | ||||||
| 	for k, v := range md { | 	for k, v := range md { | ||||||
| 		cmd[k] = v | 		nmd[k] = v | ||||||
| 	} | 	} | ||||||
| 	return cmd | 	return nmd | ||||||
| } | } | ||||||
|  |  | ||||||
| // Delete key from metadata | func Del(ctx context.Context, key string) context.Context { | ||||||
| func Delete(ctx context.Context, k string) context.Context { |  | ||||||
| 	return Set(ctx, k, "") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Set add key with val to metadata |  | ||||||
| func Set(ctx context.Context, k, v string) context.Context { |  | ||||||
| 	md, ok := FromContext(ctx) | 	md, ok := FromContext(ctx) | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		md = make(Metadata) | 		md = make(Metadata) | ||||||
| 	} | 	} | ||||||
| 	if v == "" { | 	md.Del(key) | ||||||
| 		delete(md, k) | 	return context.WithValue(ctx, metadataKey{}, md) | ||||||
| 	} else { |  | ||||||
| 		md[k] = v |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Set add key with val to metadata | ||||||
|  | func Set(ctx context.Context, key, val string) context.Context { | ||||||
|  | 	md, ok := FromContext(ctx) | ||||||
|  | 	if !ok { | ||||||
|  | 		md = make(Metadata) | ||||||
|  | 	} | ||||||
|  | 	md.Set(key, val) | ||||||
| 	return context.WithValue(ctx, metadataKey{}, md) | 	return context.WithValue(ctx, metadataKey{}, md) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -70,32 +65,13 @@ func Get(ctx context.Context, key string) (string, bool) { | |||||||
| 	if !ok { | 	if !ok { | ||||||
| 		return "", ok | 		return "", ok | ||||||
| 	} | 	} | ||||||
| 	// attempt to get as is | 	return md.Get(key) | ||||||
| 	val, ok := md[key] |  | ||||||
| 	if ok { |  | ||||||
| 		return val, ok |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// attempt to get lower case |  | ||||||
| 	val, ok = md[strings.Title(key)] |  | ||||||
|  |  | ||||||
| 	return val, ok |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // FromContext returns metadata from the given context | // FromContext returns metadata from the given context | ||||||
| func FromContext(ctx context.Context) (Metadata, bool) { | func FromContext(ctx context.Context) (Metadata, bool) { | ||||||
| 	md, ok := ctx.Value(metadataKey{}).(Metadata) | 	md, ok := ctx.Value(metadataKey{}).(Metadata) | ||||||
| 	if !ok { | 	return md, ok | ||||||
| 		return nil, ok |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// capitalise all values |  | ||||||
| 	newMD := make(Metadata, len(md)) |  | ||||||
| 	for k, v := range md { |  | ||||||
| 		newMD[strings.Title(k)] = v |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return newMD, ok |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // NewContext creates a new context with the given metadata | // NewContext creates a new context with the given metadata | ||||||
| @@ -104,23 +80,26 @@ func NewContext(ctx context.Context, md Metadata) context.Context { | |||||||
| } | } | ||||||
|  |  | ||||||
| // MergeContext merges metadata to existing metadata, overwriting if specified | // MergeContext merges metadata to existing metadata, overwriting if specified | ||||||
| func MergeContext(ctx context.Context, patchMd Metadata, overwrite bool) context.Context { | func MergeContext(ctx context.Context, pmd Metadata, overwrite bool) context.Context { | ||||||
| 	if ctx == nil { | 	if ctx == nil { | ||||||
| 		ctx = context.Background() | 		ctx = context.Background() | ||||||
| 	} | 	} | ||||||
| 	md, _ := ctx.Value(metadataKey{}).(Metadata) | 	md, ok := FromContext(ctx) | ||||||
| 	cmd := make(Metadata, len(md)) | 	if !ok { | ||||||
| 	for k, v := range md { | 		md = make(Metadata) | ||||||
| 		cmd[k] = v |  | ||||||
| 	} | 	} | ||||||
| 	for k, v := range patchMd { | 	nmd := make(Metadata, len(md)) | ||||||
| 		if _, ok := cmd[k]; ok && !overwrite { | 	for key, val := range md { | ||||||
|  | 		nmd.Set(key, val) | ||||||
|  | 	} | ||||||
|  | 	for key, val := range pmd { | ||||||
|  | 		if _, ok := nmd[key]; ok && !overwrite { | ||||||
| 			// skip | 			// skip | ||||||
| 		} else if v != "" { | 		} else if val != "" { | ||||||
| 			cmd[k] = v | 			nmd.Set(key, val) | ||||||
| 		} else { | 		} else { | ||||||
| 			delete(cmd, k) | 			nmd.Del(key) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return context.WithValue(ctx, metadataKey{}, cmd) | 	return context.WithValue(ctx, metadataKey{}, nmd) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ func TestMetadataDelete(t *testing.T) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	ctx := NewContext(context.TODO(), md) | 	ctx := NewContext(context.TODO(), md) | ||||||
| 	ctx = Delete(ctx, "Baz") | 	ctx = Del(ctx, "Baz") | ||||||
|  |  | ||||||
| 	emd, ok := FromContext(ctx) | 	emd, ok := FromContext(ctx) | ||||||
| 	if !ok { | 	if !ok { | ||||||
|   | |||||||
| @@ -3,7 +3,6 @@ package ctx | |||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/textproto" |  | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"github.com/unistack-org/micro/v3/metadata" | 	"github.com/unistack-org/micro/v3/metadata" | ||||||
| @@ -13,10 +12,11 @@ func FromRequest(r *http.Request) context.Context { | |||||||
| 	ctx := r.Context() | 	ctx := r.Context() | ||||||
| 	md, ok := metadata.FromContext(ctx) | 	md, ok := metadata.FromContext(ctx) | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		md = make(metadata.Metadata) | 		// create needed map with specific len | ||||||
|  | 		md = make(metadata.Metadata, len(r.Header)+2) | ||||||
| 	} | 	} | ||||||
| 	for k, v := range r.Header { | 	for key, val := range r.Header { | ||||||
| 		md[textproto.CanonicalMIMEHeaderKey(k)] = strings.Join(v, ",") | 		md.Set(key, strings.Join(val, ",")) | ||||||
| 	} | 	} | ||||||
| 	// pass http host | 	// pass http host | ||||||
| 	md["Host"] = r.Host | 	md["Host"] = r.Host | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user