Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kratos http parse pb message body panic #2782

Closed
qjw opened this issue Apr 12, 2023 · 0 comments · Fixed by #2847
Closed

kratos http parse pb message body panic #2782

qjw opened this issue Apr 12, 2023 · 0 comments · Fixed by #2847
Labels
bug Something isn't working

Comments

@qjw
Copy link

qjw commented Apr 12, 2023

What happened:

使用下列的pb生成 http代码, 使用 json payload正常, 但使用pb序列化后, 解析 request panic

// 客户端
message Client {
  option (google.api.resource) = {
    type: "v1.greeter.test.example.com/Client"
    pattern: "clients/{client_int32}"
  };

  // 资源名称
  string name = 1;

  // id
  int32 id = 2;

  // 状态
  ClientStatus status = 3 [(google.api.field_behavior) = OUTPUT_ONLY];

  string display_name = 4 ;
}
service ExampleService {
  // 创建Client
  // (-- api-linter: core::0133::method-signature=disabled
  //     aip.dev/not-precedent: 顶层资源无需parent --)
  rpc CreateClient(CreateClientRequest) returns (CreateClientResponse) {
    option (google.api.method_signature) = "client";
    option (google.api.http) = {
      post: "/api/v1/clients"
      body: "client"
    };
  }
}

// 创建Client请求
message CreateClientRequest {
  // 创建Client
  Client client = 1 [(google.api.field_behavior) = REQUIRED];
}

// 创建Client响应
message CreateClientResponse {
  // 创建Client响应
  Client client = 1 [(google.api.field_behavior) = REQUIRED];
}

从json转成pb,后端无需修改代码, 前端修改 Content-Type : application/proto. 具体的代码实现在 github.com/go-kratos/kratos/v2/transport/http/codec.go

// CodecForRequest get encoding.Codec via http.Request
func CodecForRequest(r *http.Request, name string) (encoding.Codec, bool) {
	for _, accept := range r.Header[name] {
		codec := encoding.GetCodec(httputil.ContentSubtype(accept))
		if codec != nil {
			return codec, true
		}
	}
	return encoding.GetCodec("json"), false
}

原因

panic 日志

2023/04/12 14:16:11 http: panic serving 192.168.105.20:49928: interface conversion: **v1.Client is not protoreflect.ProtoMessage: missing method ProtoReflect
goroutine 107 [running]:
net/http.(*conn).serve.func1()
	/data/go1.19/src/net/http/server.go:1850 +0x148
panic({0x13f86a0, 0xc0004aa480})
	/data/go1.19/src/runtime/panic.go:890 +0x267
github.com/go-kratos/kratos/v2/encoding/proto.codec.Unmarshal({}, {0xc000570400, 0x13, 0x200}, {0x134db20, 0xc0004aa478})
	/data/common/kratos-layout/vendor/github.com/go-kratos/kratos/v2/encoding/proto/proto.go:26 +0x67
github.com/go-kratos/kratos/v2/transport/http.DefaultRequestDecoder(0xc00050cc00, {0x134db20, 0xc0004aa478})
	/data/common/kratos-layout/vendor/github.com/go-kratos/kratos/v2/transport/http/codec.go:72 +0x286
github.com/go-kratos/kratos/v2/transport/http.(*wrapper).Bind(0xc000518980, {0x134db20, 0xc0004aa478})
	/data/common/kratos-layout/vendor/github.com/go-kratos/kratos/v2/transport/http/context.go:99 +0x62
go.example.com/apis/lixin/test/kratos-layout/v1._KratoLayoutService_CreateClient0_HTTP_Handler.func1({0x7f03b05effc8, 0xc000518980})

github.com/go-kratos/kratos/v2/encoding/proto/proto.go

func (codec) Unmarshal(data []byte, v interface{}) error {
       // v 是一个二级指针 (**Client)
       // v 是一个二级指针 (**Client)
       // v 是一个二级指针 (**Client)
	return proto.Unmarshal(data, v.(proto.Message))
}

生成的Go代码如下

// 创建Client请求
type CreateClientRequest struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	// 注意这里是指针
	// 注意这里是指针
	// 注意这里是指针
	Client *Client `protobuf:"bytes,1,opt,name=client,proto3" json:"client,omitempty"`
}

func _KratoLayoutService_CreateClient0_HTTP_Handler(srv KratoLayoutServiceHTTPServer) func(ctx http.Context) error {
	return func(ctx http.Context) error {
		var in CreateClientRequest

                // 这里进一步取指针的地址
                // 这里进一步取指针的地址
                // 这里进一步取指针的地址
		if err := ctx.Bind(&in.Client); err != nil {
			return err
		}

                // 。。。。。。。
		return ctx.Result(200, reply)
	}
}

image

What you expected to happen:

How to reproduce it (as minimally and precisely as possible):

Anything else we need to know?:

Environment:

  • Kratos version (use kratos -v): github.com/go-kratos/kratos/v2 v2.5.3
  • Go version (use go version): 1.19
  • OS (e.g: cat /etc/os-release):

NAME="Ubuntu"
VERSION="20.04.3 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.3 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

  • Others:
@qjw qjw added the bug Something isn't working label Apr 12, 2023
@kratos-ci-bot kratos-ci-bot changed the title kratos http 解析 pb 消息体 panic kratos http parse pb message body panic Apr 12, 2023
shifengbin added a commit to shifengbin/kratos that referenced this issue May 24, 2023
shifengbin added a commit to shifengbin/kratos that referenced this issue May 24, 2023
shenqidebaozi pushed a commit that referenced this issue May 29, 2023
* fix: issue #2782

* fix: issue #2782 rename

* fix: make fix
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant