Adven27 / grpc-wiremock

gRPC Mock Server
MIT License
93 stars 40 forks source link

gRPC restricted header name: "content-length" #33

Closed mehmetcuneyit closed 2 years ago

mehmetcuneyit commented 2 years ago

Describe the bug I appreciate your efforts on this project. It's really simple to use for my needs. I was doing gRPC tests through APISIX gateway. I set up grpc-wiremock as backend service to respond gRPC requests coming from APISIX gRPC-transcoder (transforms http to gRPC). To Reproduce Request flow is like curl -> APISIX gateway ( gRPC transcoder )-> grpc-wiremock Steps to reproduce the behavior:

  1. Set up APISIX gateway and push proto descriptor binary to the gateway using the sample proto files
  2. Create an upstream entry that points a grpc-wiremock instance (make sure they are in the same network for simplicity)
  3. Create route in the gateway(127.0.0.1:9080) similar to below
    curl http://127.0.0.1:9080/apisix/admin/routes/111 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
    {
    "methods": ["GET"],
    "uri": "/userBalance",
    "plugins": {
        "grpc-transcode": {
            "proto_id": "1",
            "service": "api.wallet.BalanceService",
            "method": "getUserBalance"
        }
    },
    }'
  4. Send curl json request to the gateway(127.0.0.1:9080) which will be converted to gRPC message and will be passed to grpc-wiremock
    curl -i http://127.0.0.1:9080/userBalance\?user_id\=1\&currency\=EUR
  5. See error in the grpc-wiremock logs
    
    2022-03-25 14:13:17.637  INFO 306 --- [ault-executor-7] io.adven.grpc.wiremock.HttpMock          : Grpc request BalanceService/getUserBalance:
    Headers: {x-grpc-full-method-name=api.wallet.BalanceService/getUserBalance, withamount=100.0, content-length=12, content-type=application/grpc, user-agent=curl/7.81.0, accept=*/*}
    Message:
    user_id: 1
    currency: "EUR"

2022-03-25 14:13:17.638 ERROR 306 --- [ault-executor-7] io.grpc.internal.SerializingExecutor : Exception while executing runnable io.grpc.internal.ServerImpl$JumpToApplicationThreadServerStreamListener$1HalfClosed@5b32676d

java.lang.IllegalArgumentException: restricted header name: "content-length" at java.net.http/jdk.internal.net.http.common.Utils.newIAE(Utils.java:286) ~[java.net.http:na] at java.net.http/jdk.internal.net.http.HttpRequestBuilderImpl.checkNameAndValue(HttpRequestBuilderImpl.java:110) ~[java.net.http:na] at java.net.http/jdk.internal.net.http.HttpRequestBuilderImpl.header(HttpRequestBuilderImpl.java:126) ~[java.net.http:na] at java.net.http/jdk.internal.net.http.HttpRequestBuilderImpl.headers(HttpRequestBuilderImpl.java:140) ~[java.net.http:na] at java.net.http/jdk.internal.net.http.HttpRequestBuilderImpl.headers(HttpRequestBuilderImpl.java:43) ~[java.net.http:na] at io.adven.grpc.wiremock.HttpMock.request(HttpMock.java:88) ~[main/:na] at io.adven.grpc.wiremock.HttpMock.request(HttpMock.java:97) ~[main/:na] at io.adven.grpc.wiremock.Translator$WireMockTranslator.redirect(Translator.java:44) ~[main/:na] at io.adven.grpc.wiremock.Translator$WireMockTranslator.redirectApiWalletBalanceService(Translator.java:56) ~[main/:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:634) ~[spring-aop-5.3.14.jar:5.3.14] at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:624) ~[spring-aop-5.3.14.jar:5.3.14] at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:72) ~[spring-aop-5.3.14.jar:5.3.14] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.14.jar:5.3.14] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753) ~[spring-aop-5.3.14.jar:5.3.14] at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.14.jar:5.3.14] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.14.jar:5.3.14] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753) ~[spring-aop-5.3.14.jar:5.3.14] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698) ~[spring-aop-5.3.14.jar:5.3.14] at io.adven.grpc.wiremock.Translator$ApiWalletBalanceService$$EnhancerBySpringCGLIB$$26d39afa.getUserBalance() ~[main/:na] at api.wallet.BalanceServiceGrpc$MethodHandlers.invoke(BalanceServiceGrpc.java:205) ~[main/:na] at io.grpc.stub.ServerCalls$UnaryServerCallHandler$UnaryServerCallListener.onHalfClose(ServerCalls.java:182) ~[grpc-stub-1.43.2.jar:1.43.2] at io.grpc.PartialForwardingServerCallListener.onHalfClose(PartialForwardingServerCallListener.java:35) ~[grpc-api-1.43.2.jar:1.43.2] at io.grpc.ForwardingServerCallListener.onHalfClose(ForwardingServerCallListener.java:23) ~[grpc-api-1.43.2.jar:1.43.2] at io.grpc.ForwardingServerCallListener$SimpleForwardingServerCallListener.onHalfClose(ForwardingServerCallListener.java:40) ~[grpc-api-1.43.2.jar:1.43.2] at io.grpc.Contexts$ContextualizedServerCallListener.onHalfClose(Contexts.java:86) ~[grpc-api-1.43.2.jar:1.43.2] at io.grpc.PartialForwardingServerCallListener.onHalfClose(PartialForwardingServerCallListener.java:35) ~[grpc-api-1.43.2.jar:1.43.2] at io.grpc.ForwardingServerCallListener.onHalfClose(ForwardingServerCallListener.java:23) ~[grpc-api-1.43.2.jar:1.43.2] at io.grpc.ForwardingServerCallListener$SimpleForwardingServerCallListener.onHalfClose(ForwardingServerCallListener.java:40) ~[grpc-api-1.43.2.jar:1.43.2] at io.adven.grpc.wiremock.ExceptionHandler$ExceptionHandlingServerCallListener.onHalfClose(ExceptionHandler.java:42) ~[main/:na] at io.grpc.internal.ServerCallImpl$ServerStreamListenerImpl.halfClosed(ServerCallImpl.java:340) ~[grpc-core-1.43.2.jar:1.43.2] at io.grpc.internal.ServerImpl$JumpToApplicationThreadServerStreamListener$1HalfClosed.runInContext(ServerImpl.java:866) ~[grpc-core-1.43.2.jar:1.43.2] at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37) ~[grpc-core-1.43.2.jar:1.43.2] at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133) ~[grpc-core-1.43.2.jar:1.43.2] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na] at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]



**Expected behavior**
grpc-wiremock should not throw an exception if `content-length` field set in the request header.

**Additional context**
APISIX plugin gRPC-transcoder translates http json request to gRPC proto messages. It sets `content-length` after the conversion, so it triggers the exception.