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

Fix empty GET request codec translation #122

Merged
merged 10 commits into from
Apr 11, 2024

Conversation

ls-aron-kyle
Copy link
Contributor

@ls-aron-kyle ls-aron-kyle commented Apr 10, 2024

Requiring request prep for all requests except for body: "*"

@CLAassistant
Copy link

CLAassistant commented Apr 10, 2024

CLA assistant check
All committers have signed the CLA.

Copy link
Collaborator

@emcfarlane emcfarlane left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking into this! Would you be able to create a testcase in the file vanguard_restxrpc_test.go. You'll have to update the proto files under internal/proto/vanguard to cover the case. As this was an oversight in the testing, and isn't currently covered. To keep with the theme maybe in library.proto:

  // Lists shelves.
  rpc ListShelves(ListShelvesRequest) returns (ListShelvesResponse) {
    // List method maps to HTTP GET.
    option (google.api.http) = {
      get: "/v1/shelves"
    };
  }

And the testcase something like:

	}, {
		name: "ListShelves-GetNilRequest",
		input: input{
			method: http.MethodGet,
			path:   "/v1/shelves",
			body:   nil,
		},
		stream: testStream{
			method: testv1connect.LibraryServiceListShelvesProcedure,
			msgs: []testMsg{
				{in: &testMsgIn{
					msg: &testv1.ListShelvesRequest{},
				}},
				{out: &testMsgOut{
					msg: &testv1.ListShelvesResponse{},
				}},
			},
		},
		output: output{
			code: http.StatusOK,
			body: &testv1.ListShelvesResponse{},
		},

protocol_rest.go Outdated
}

func restHTTPBodyRequestIsEmpty(op *operation) bool {
return op.request.ContentLength < 0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is checking for an unknown ContentLength as -1 is valid for a non empty body where the content-length can't be deduced up front.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added some unit tests and took another stab at it using the restTarget values.

I'm open to other fixes.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the issue is here:

case m.isRequest && op.clientReqNeedsPrep:

We need to not fallthrough to the default case as an empty body is not a valid JSON request. We must always use the prepareUnmarshalRequest for decoding the message if needed. We also must always emit a request message when we hit EOF here:

vanguard-go/transcoder.go

Lines 952 to 953 in 7aae240

if !r.consumedFirst && errors.Is(err, io.EOF) && r.rw.op.clientReqNeedsPrep {
r.msg.markReady()

I think for now the simplest fix is for any GET request to return true on requestNeedsPrep. So this would add a simple op.request.Method == http.MethodGET to the logic . The prepareUnmarshaledRequest is close to a no-op so shouldn't add much overhead. And almost all GET requests will require preparation of the request message.

Copy link
Member

@jhump jhump left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really understand this change.

For one, why does the request need preparation if the body is empty but all of those other conditions are false? That doesn't seem intuitive. The "request preparation" is to adjust the request -- based on other aspects of the request (like URI path, query string, etc) or to transform the request data when using google.api.HttpBody.

Also, the helper function looks wrong. If the ContentLength field of an *http.Request is less than zero, it means that the length of the body is not known -- i.e. you must actually read the body. This is common for HTTP/2 and HTTP 1.1 chunked requests.

protocol_rest.go Outdated Show resolved Hide resolved
internal/proto/vanguard/test/v1/library.proto Outdated Show resolved Hide resolved
vanguard_restxrpc_test.go Outdated Show resolved Hide resolved
ls-aron-kyle and others added 4 commits April 11, 2024 15:20
Co-authored-by: Edward McFarlane <[email protected]>
Small addition to make the request look more like a real list request. This proto file acts as documentation for building a REST style API.

Co-authored-by: Edward McFarlane <[email protected]>
Co-authored-by: Edward McFarlane <[email protected]>
@emcfarlane emcfarlane changed the title issue-121: Adding check for empty request body as needing request prep. Fix empty GET request codec translation Apr 11, 2024
Copy link
Collaborator

@emcfarlane emcfarlane left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks!

protocol_rest.go Outdated Show resolved Hide resolved
protocol_rest.go Outdated Show resolved Hide resolved
@ls-aron-kyle ls-aron-kyle changed the title Fix empty GET request codec translation Fix empty GET request codec translation (#121) Apr 11, 2024
protocol_rest.go Outdated Show resolved Hide resolved
@emcfarlane emcfarlane merged commit 3f05bb5 into connectrpc:main Apr 11, 2024
5 checks passed
@emcfarlane emcfarlane changed the title Fix empty GET request codec translation (#121) Fix empty GET request codec translation Apr 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants