Repository: go-kratos/kratos
Pull request #714 (2021-02-20 10:20:30)

repair tracing opentracing.HTTPHeadersCarrier panic
修复grpc下未初始化opentracing.HTTPHeadersCarrier引起的panic


Patch:
diff --git a/cmd/protoc-gen-go-http/template.go b/cmd/protoc-gen-go-http/template.go
index 61831956..c4f5cc44 100644
--- a/cmd/protoc-gen-go-http/template.go
+++ b/cmd/protoc-gen-go-http/template.go
@@ -18,11 +18,6 @@ func Register{{.ServiceType}}HTTPServer(s http1.ServiceRegistrar, srv {{.Service
 {{range .Methods}}
 func _HTTP_{{$.ServiceType}}_{{.Name}}_{{.Num}}(srv interface{}, ctx context.Context, req *http.Request, dec func(interface{}) error) (interface{}, error) {
 	var in {{.Request}}
-{{if ne (len .Vars) 0}}
-	if err := http1.BindVars(req, &in); err != nil {
-		return nil, err
-	}
-{{end}}
 {{if eq .Body ""}}
 	if err := http1.BindForm(req, &in); err != nil {
 		return nil, err
@@ -35,6 +30,11 @@ func _HTTP_{{$.ServiceType}}_{{.Name}}_{{.Num}}(srv interface{}, ctx context.Con
 	if err := dec(in{{.Body}}); err != nil {
 		return nil, err
 	}
+{{end}}
+{{if ne (len .Vars) 0}}
+	if err := http1.BindVars(req, &in); err != nil {
+		return nil, err
+	}
 {{end}}
 	out, err := srv.({{$.ServiceType}}Server).{{.Name}}(ctx, &in)
 	if err != nil {
diff --git a/config/README.md b/config/README.md
index be6d0b9f..72a5b4df 100644
--- a/config/README.md
+++ b/config/README.md
@@ -3,39 +3,3 @@
 * [Etcd](https://github.com/go-kratos/etcd)
 * [Kube](https://github.com/go-kratos/kube)
 
-### Example Usage
-可以指定多个配置源，config 会进行合并成 map[string]interface{}，然后通过 Scan 或者 Value 获取值内容；
-
-```
-c := config.New(
-    config.WithSource(
-        file.NewSource(path),
-    ),
-    config.WithDecoder(func(kv *config.KeyValue, v map[string]interface{}) error {
-        // kv.Key
-        // kv.Value
-        // kv.Metadata
-        // 自定义实现对应的数据源解析，如果是配置中心数据源也可以指定metadata进行识别配置类型
-        return yaml.Unmarshal(kv.Value, v)
-    }),
-)
-// 加载配置源：
-if err := c.Load(); err != nil {
-    panic(err)
-}
-// 获取对应的值内容：
-name, err := c.Value("service").String()
-// 解析到结构体（由于已经合并到map[string]interface{}，所以需要指定 jsonName 进行解析）：
-var v struct {
-    Service string `json:"service"`
-    Version string `json:"version"`
-}
-if err := c.Scan(&v); err != nil {
-    panic(err)
-}
-// 监听值内容变更
-c.Watch("service.name", func(key string, value config.Value) {
-    // 值内容变更
-})
-```
-
diff --git a/middleware/metrics/metrics.go b/middleware/metrics/metrics.go
index c054ae97..d27fe7bb 100644
--- a/middleware/metrics/metrics.go
+++ b/middleware/metrics/metrics.go
@@ -92,17 +92,12 @@ func Client(opts ...Option) middleware.Middleware {
 				path   string
 				code   int32
 			)
-			if info, ok := grpc.FromServerContext(ctx); ok {
+			if info, ok := grpc.FromClientContext(ctx); ok {
 				method = "POST"
 				path = info.FullMethod
-			} else if info, ok := http.FromServerContext(ctx); ok {
+			} else if info, ok := http.FromClientContext(ctx); ok {
 				method = info.Request.Method
-				if route := mux.CurrentRoute(info.Request); route != nil {
-					// /path/123 -> /path/{id}
-					path, _ = route.GetPathTemplate()
-				} else {
-					path = info.Request.RequestURI
-				}
+				path = info.Request.RequestURI
 			}
 			startTime := time.Now()
 			reply, err := handler(ctx, req)
diff --git a/middleware/tracing/tracing.go b/middleware/tracing/tracing.go
index bf4779ae..cd3212cc 100644
--- a/middleware/tracing/tracing.go
+++ b/middleware/tracing/tracing.go
@@ -104,6 +104,10 @@ func Client(opts ...Option) middleware.Middleware {
 				if md, ok := metadata.FromOutgoingContext(ctx); ok {
 					carrier = opentracing.HTTPHeadersCarrier(md)
 					ctx = metadata.NewOutgoingContext(ctx, md)
+				} else {
+					md = metadata.Pairs()
+					carrier = opentracing.HTTPHeadersCarrier(md)
+					ctx = metadata.NewOutgoingContext(ctx, md)
 				}
 			}
 			span := options.tracer.StartSpan(
diff --git a/transport/http/default.go b/transport/http/default.go
index 61f7e157..d1a59e95 100644
--- a/transport/http/default.go
+++ b/transport/http/default.go
@@ -25,9 +25,9 @@ func contentSubtype(contentType string) string {
 	// guaranteed since != baseContentType and has baseContentType prefix
 	switch contentType[len(baseContentType)] {
 	case '/', ';':
-		// this will return true for "application/grpc+" or "application/grpc;"
-		// which the previous validContentType function tested to be valid, so we
-		// just say that no content-subtype is specified in this case
+		if i := strings.Index(contentType, ";"); i != -1 {
+			return contentType[len(baseContentType)+1 : i]
+		}
 		return contentType[len(baseContentType)+1:]
 	default:
 		return ""
diff --git a/transport/http/server.go b/transport/http/server.go
index a4dd39ce..4e42f9fb 100644
--- a/transport/http/server.go
+++ b/transport/http/server.go
@@ -110,7 +110,7 @@ func NewServer(opts ...ServerOption) *Server {
 	return srv
 }
 
-// RouteGroup .
+// RouteGroup returns a new route group for the URL path prefix.
 func (s *Server) RouteGroup(prefix string) *RouteGroup {
 	return &RouteGroup{prefix: prefix, router: s.router}
 }
@@ -125,6 +125,11 @@ func (s *Server) HandleFunc(path string, h http.HandlerFunc) {
 	s.router.HandleFunc(path, h)
 }
 
+// PrefixHanlde  registers a new route with a matcher for the URL path prefix.
+func (s *Server) PrefixHanlde(prefix string, h http.Handler) {
+	s.router.PathPrefix(prefix).Handler(h)
+}
+
 // ServeHTTP should write reply headers and data to the ResponseWriter and then return.
 func (s *Server) ServeHTTP(res http.ResponseWriter, req *http.Request) {
 	ctx, cancel := context.WithTimeout(req.Context(), s.timeout)


Test patch:
diff --git a/transport/http/default_test.go b/transport/http/default_test.go
new file mode 100644
index 00000000..044f5be2
--- /dev/null
+++ b/transport/http/default_test.go
@@ -0,0 +1,23 @@
+package http
+
+import "testing"
+
+func TestSubtype(t *testing.T) {
+	tests := []struct {
+		input    string
+		expected string
+	}{
+		{"application/json", "json"},
+		{"application/json;", "json"},
+		{"application/json; charset=utf-8", "json"},
+		{"application/", ""},
+		{"application", ""},
+		{"foo", ""},
+		{"", ""},
+	}
+	for _, test := range tests {
+		if contentSubtype(test.input) != test.expected {
+			t.Errorf("expected %s got %s", test.expected, test.input)
+		}
+	}
+}