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

gRPC client regression in case of non 200 HTTP response #90

Closed
laurentvaills opened this issue Mar 17, 2021 · 7 comments
Closed

gRPC client regression in case of non 200 HTTP response #90

laurentvaills opened this issue Mar 17, 2021 · 7 comments
Labels
Milestone

Comments

@laurentvaills
Copy link

I noticed that when upgrading my gRPC client from Vert.x 4.0.2 to 4.0.3, then it is not able to handle properly the HTTP responses with a status different than 200 (at least with status 401 and 403).

Indeed gRPC relies on HTTP/2 for its transport and before reaching the gRPC server, the gRPC request can go through multiple intermediaries (HTTP proxies). And such intermediary can check the incoming HTTP request and decide to forward it or to stop it by sending a plain HTTP response. The client then can map the HTTP status code to a gRPC one, as described on
https://grpc.github.io/grpc/core/md_doc_http-grpc-status-mapping.html .

The setup to reproduce is pretty simple:

  • have a plain HTTP server that answers only 401
  • have a gRPC client that send a gRPC request to that host.

With Vert.x 4.0.2 that works as expected: a StatusRuntimeException is raised and the Status attached to this Exception is UNAUTHENTICATED. Here is the output:

Could not reach server UNAUTHENTICATED: HTTP status code 401
invalid content-type: null
trailers: Metadata(:status=401,content-length=0)
Status: Status{code=UNAUTHENTICATED, description=HTTP status code 401
invalid content-type: null
trailers: Metadata(:status=401,content-length=0), cause=null}

With Vert.x 4.0.3 that does not work so well: StatusRuntimeException is raised but the Status attached to this Exception is UNKNOWN and we have the following traces:

Could not reach server UNKNOWN
Status: Status{code=UNKNOWN, description=null, cause=java.lang.UnsupportedOperationException
	at io.grpc.netty.AbstractHttp2Headers.setLong(AbstractHttp2Headers.java:465)
	at io.grpc.netty.AbstractHttp2Headers.setLong(AbstractHttp2Headers.java:26)
	at io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder$FrameReadListener.onHeadersRead(DefaultHttp2ConnectionDecoder.java:403)
	at io.netty.handler.codec.http2.Http2InboundFrameLogger$1.onHeadersRead(Http2InboundFrameLogger.java:65)
	at io.netty.handler.codec.http2.DefaultHttp2FrameReader$1.processFragment(DefaultHttp2FrameReader.java:457)
	at io.netty.handler.codec.http2.DefaultHttp2FrameReader.readHeadersFrame(DefaultHttp2FrameReader.java:464)
	at io.netty.handler.codec.http2.DefaultHttp2FrameReader.processPayloadState(DefaultHttp2FrameReader.java:254)
	at io.netty.handler.codec.http2.DefaultHttp2FrameReader.readFrame(DefaultHttp2FrameReader.java:160)
	at io.netty.handler.codec.http2.Http2InboundFrameLogger.readFrame(Http2InboundFrameLogger.java:41)
	at io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder.decodeFrame(DefaultHttp2ConnectionDecoder.java:181)
	at io.netty.handler.codec.http2.Http2ConnectionHandler$FrameDecoder.decode(Http2ConnectionHandler.java:378)
	at io.netty.handler.codec.http2.Http2ConnectionHandler.decode(Http2ConnectionHandler.java:438)
	at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508)
...
}

It seems that with Vert.x 4.0.3, the parsing of the HTTP/2 headers fail so the status default to UNKNOWN . So of course that has impacts when we have to take decision based on that Exception's Status.

After a few tries with forcing different versions of Netty, I found that this regression is coming in Netty 4.1.60.Final.
With Vert.x 4.0.3 but forcing Netty to 4.1.59.Final it is working fine.

Find attached the small test I use to emphasize this regression, it is fully based on the gRPC example you documented on : https://vertx.io/docs/vertx-grpc/java/ . See the class Client.

vertx-grpc-example.zip

@laurentvaills
Copy link
Author

laurentvaills commented Mar 17, 2021

Digging a bit more on the problem I found the following grpc-java pull-request that seem to address that problem grpc/grpc-java#7967 .

But also that reported issue seems similar: grpc/grpc-java#7953 .

@laurentvaills
Copy link
Author

grpc-java has backported the fix on 1.35.x branch and has just released a 1.35.1 , so that it is compatible with Netty 4.1.60.Final , that Vert.x 4.0.3 is depending on : https://github.com/grpc/grpc-java/releases/tag/v1.35.1

@vietj
Copy link
Contributor

vietj commented Mar 29, 2021 via email

@vietj
Copy link
Contributor

vietj commented Mar 29, 2021

we had a similar issue with Vertx HTTP header implementation

@vietj
Copy link
Contributor

vietj commented Mar 29, 2021

see #92

@vietj vietj closed this as completed Mar 29, 2021
@vietj vietj added this to the 4.0.4 milestone Mar 29, 2021
@vietj
Copy link
Contributor

vietj commented Mar 29, 2021

thanks for the investigation @laurentvaills can you check now it is fine with the snapshots ?

@vietj vietj modified the milestones: 4.0.4, 4.1.0 Mar 30, 2021
@laurentvaills
Copy link
Author

@vietj In my pet example with Vert.x 4.0.4-SNAPSHOT it is working as before : I get the status UNAUTHENTICATED if the gRPC server answers with a 401.

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

2 participants