mock-server / mockserver

MockServer enables easy mocking of any system you integrate with via HTTP or HTTPS with clients written in Java, JavaScript and Ruby. MockServer also includes a proxy that introspects all proxied traffic including encrypted SSL traffic and supports Port Forwarding, Web Proxying (i.e. HTTP proxy), HTTPS Tunneling Proxying (using HTTP CONNECT) and SOCKS Proxying (i.e. dynamic port forwarding).
http://mock-server.com
Apache License 2.0
4.57k stars 1.07k forks source link

Channel set as inactive before valid response has been received #420

Closed dimirtyg closed 5 years ago

dimirtyg commented 6 years ago

Hello I deployed Mockserver from docker image (jamesdbloom/mockserver). After that I set expectations by curl -v -X PUT ":1080/expectation" -d '{ "httpRequest" : { "method" : "GET", "path" : "/view/cart"}, "httpResponse" : {"body" : "some_response_body"}}'

and I able to get response first time by curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET :1080/view/cart

However, when I run preceding curl command second time it fails as below. Is it a bug? What is solution/workaround? Thanks in advance! Dimitry

Error 2018-01-24 03:55:14,005 ERROR o.m.m.HttpStateHandler Exception processing { "method" : "GET", "path" : "/view/cart", "headers" : { "User-Agent" : [ "curl/7.49.1" ], "Accept" : [ "application/json" ], "Content-Type" : [ "application/json" ], "host" : [ "a176448f5fffa11e7ac720a19521a2cc-1910945988.eu-west-1.elb.amazonaws.com:1080" ], "accept-encoding" : [ "gzip,deflate" ], "content-length" : [ "0" ], "connection" : [ "keep-alive" ] }, "keepAlive" : true, "secure" : false } java.lang.RuntimeException: Exception while sending request - java.lang.RuntimeException: Channel set as inactive before valid response has been received at org.mockserver.client.netty.NettyHttpClient.sendRequest(NettyHttpClient.java:101) ~[mockserver-netty-jar-with-dependencies.jar:na] at org.mockserver.mock.action.ActionHandler.processAction(ActionHandler.java:111) ~[mockserver-netty-jar-with-dependencies.jar:na] at org.mockserver.mockserver.MockServerHandler.channelRead0(MockServerHandler.java:107) [mockserver-netty-jar-with-dependencies.jar:na] at org.mockserver.mockserver.MockServerHandler.channelRead0(MockServerHandler.java:37) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:108) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:284) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [mockserver-netty-jar-with-dependencies.jar:na] at org.mockserver.unification.PortUnificationHandler.switchToHttp(PortUnificationHandler.java:188) [mockserver-netty-jar-with-dependencies.jar:na] at org.mockserver.unification.PortUnificationHandler.channelRead0(PortUnificationHandler.java:91) [mockserver-netty-jar-with-dependencies.jar:na] at org.mockserver.unification.PortUnificationHandler.channelRead0(PortUnificationHandler.java:37) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1359) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:935) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:138) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:645) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:138) [mockserver-netty-jar-with-dependencies.jar:na] at java.lang.Thread.run(Thread.java:748) [na:1.8.0_151] Caused by: java.util.concurrent.ExecutionException: java.lang.RuntimeException: Channel set as inactive before valid response has been received at com.google.common.util.concurrent.AbstractFuture$Sync.getValue(AbstractFuture.java:299) ~[mockserver-netty-jar-with-dependencies.jar:na] at com.google.common.util.concurrent.AbstractFuture$Sync.get(AbstractFuture.java:272) ~[mockserver-netty-jar-with-dependencies.jar:na] at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:96) ~[mockserver-netty-jar-with-dependencies.jar:na] at org.mockserver.client.netty.NettyHttpClient.sendRequest(NettyHttpClient.java:80) ~[mockserver-netty-jar-with-dependencies.jar:na] ... 51 common frames omitted Caused by: java.lang.RuntimeException: Channel set as inactive before valid response has been received at org.mockserver.client.netty.HttpClientConnectionHandler.updatePromise(HttpClientConnectionHandler.java:19) ~[mockserver-netty-jar-with-dependencies.jar:na] at org.mockserver.client.netty.HttpClientConnectionHandler.channelInactive(HttpClientConnectionHandler.java:25) ~[mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:245) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:231) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:224) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.DefaultChannelPipeline$HeadContext.channelInactive(DefaultChannelPipeline.java:1354) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:245) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:231) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.DefaultChannelPipeline.fireChannelInactive(DefaultChannelPipeline.java:917) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannel$AbstractUnsafe$8.run(AbstractChannel.java:822) ~[mockserver-netty-jar-with-dependencies.jar:na] at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163) ~[mockserver-netty-jar-with-dependencies.jar:na] at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:403) ~[mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:463) [mockserver-netty-jar-with-dependencies.jar:na] ... 3 common frames omitted

jamesdbloom commented 6 years ago

I can't reproduce your issue as shown below.

What version of curl are you using because when I try you version of the curl command on both curl 7.35.0 (x86_64-pc-linux-gnu) and curl 7.57.0 (x86_64-apple-darwin17.2.0) doesn't work because it requires an actual ip address or hostname.

It looks like the issue may be caused by MockServer attempting to proxy your request onwards and not receiving any response before the onwards socket has been closed. Perhaps your instance of curl is setting an invalid Host header?

When I run the following curl commands:

$ curl -v -X PUT "http://127.0.0.1:1080/expectation" -d '{ "httpRequest" : { "method" : "GET", "path" : "/view/cart"}, "httpResponse" : {"body" : "some_response_body"}}'
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 1080 (#0)
> PUT /expectation HTTP/1.1
> Host: 127.0.0.1:1080
> User-Agent: curl/7.57.0
> Accept: */*
> Content-Length: 111
> Content-Type: application/x-www-form-urlencoded
> 
* upload completely sent off: 111 out of 111 bytes
< HTTP/1.1 201 Created
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: CONNECT, DELETE, GET, HEAD, OPTIONS, POST, PUT, TRACE
< Access-Control-Allow-Headers: Allow, Content-Encoding, Content-Length, Content-Type, ETag, Expires, Last-Modified, Location, Server, Vary
< Access-Control-Expose-Headers: Allow, Content-Encoding, Content-Length, Content-Type, ETag, Expires, Last-Modified, Location, Server, Vary
< Access-Control-Max-Age: 300
< X-CORS: MockServer CORS support enabled by default, to disable ConfigurationProperties.enableCORSForAPI(false) or -Dmockserver.disableCORS=false
< connection: keep-alive
< content-length: 0
< 
* Connection #0 to host 127.0.0.1 left intact

$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://127.0.0.1:1080/view/cart
HTTP/1.1 200 OK
connection: keep-alive
content-length: 18

$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://127.0.0.1:1080/view/cart
HTTP/1.1 404 Not Found
connection: keep-alive

For the following docker container I get the following log output:

$ docker run -p 1080:1080 jamesdbloom/mockserver

java  -Dfile.encoding=UTF-8 -Dmockserver.logLevel=INFO -jar /opt/mockserver/mockserver-netty-jar-with-dependencies.jar -serverPort 1080 -proxyPort 1090

2018-01-25 13:31:13,639 INFO o.m.p.http.HttpProxy MockServer started on port: 1090
2018-01-25 13:31:13,625 INFO o.m.m.MockServer MockServer started on port: 1080
2018-01-25 13:31:18,757 INFO o.m.m.HttpStateHandler creating expectation:

    {
      "httpRequest" : {
        "method" : "GET",
        "path" : "/view/cart"
      },
      "times" : {
        "remainingTimes" : 1,
        "unlimited" : false
      },
      "timeToLive" : {
        "unlimited" : true
      },
      "httpResponse" : {
        "body" : "some_response_body"
      }
    }

2018-01-25 13:31:47,053 INFO o.m.m.HttpStateHandler request:

    {
      "method" : "GET",
      "path" : "/view/cart",
      "headers" : {
        "content-length" : [ "0" ],
        "Accept" : [ "application/json" ],
        "User-Agent" : [ "curl/7.57.0" ],
        "Host" : [ "127.0.0.1:1080" ],
        "Content-Type" : [ "application/json" ]
      },
      "keepAlive" : true,
      "secure" : false
    }

 matched expectation:

    {
      "method" : "GET",
      "path" : "/view/cart"
    }

2018-01-25 13:31:47,062 INFO o.m.m.HttpStateHandler returning response:

    {
      "headers" : {
        "connection" : [ "keep-alive" ]
      },
      "body" : "some_response_body"
    }

 for request:

    {
      "method" : "GET",
      "path" : "/view/cart",
      "headers" : {
        "content-length" : [ "0" ],
        "Accept" : [ "application/json" ],
        "User-Agent" : [ "curl/7.57.0" ],
        "Host" : [ "127.0.0.1:1080" ],
        "Content-Type" : [ "application/json" ]
      },
      "keepAlive" : true,
      "secure" : false
    }

 for response action:

    {
      "body" : "some_response_body"
    }

2018-01-25 13:31:48,423 INFO o.m.m.HttpStateHandler no active expectations when receiving request:

    {
      "method" : "GET",
      "path" : "/view/cart",
      "headers" : {
        "content-length" : [ "0" ],
        "Accept" : [ "application/json" ],
        "User-Agent" : [ "curl/7.57.0" ],
        "Host" : [ "127.0.0.1:1080" ],
        "Content-Type" : [ "application/json" ]
      },
      "keepAlive" : true,
      "secure" : false
    }

2018-01-25 13:31:48,442 INFO o.m.m.HttpStateHandler no matching expectation - returning:

    {
      "statusCode" : 404,
      "reasonPhrase" : "Not Found"
    }

 for request:

    {
      "method" : "GET",
      "path" : "/view/cart",
      "headers" : {
        "content-length" : [ "0" ],
        "Accept" : [ "application/json" ],
        "User-Agent" : [ "curl/7.57.0" ],
        "Host" : [ "127.0.0.1:1080" ],
        "Content-Type" : [ "application/json" ]
      },
      "keepAlive" : true,
      "secure" : false
    }
dimirtyg commented 6 years ago

James, You are right, the issue does not repro locally. It is only reproes if I deploy mock server to our Amazon kubernetes cluster.

Basically using yaml below, I created mock server and use public elb endpoint to send requests to it. After that I hit the issue that I described above.

It seems not related to curl version as it works as far as there are active expectation on given ulr path. Could you help more to understand the issue? Could it be something generic as related to Kubernetes? Thanks a lot! Dima

Create mock

kubectl create -f replica.yaml
kubectl expose replicaset plm-mock-9 --type=LoadBalancer --port=1080 --target-port=1080 --name  plm-mock-9-http

replica.yaml

apiVersion: apps/v1beta2 
kind: ReplicaSet
metadata:
  name: plm-mock-9
  labels:
    app: plm-mock-9
spec:
  replicas: 1
  selector:
    matchLabels:
      app: plm-mock-9
  template:
    metadata:
      labels:
        app: plm-mock-9
    spec:
      containers:
      - name: plm-mock-9
        image: jamesdbloom/mockserver
        resources:
          limits:
            cpu: "1"
            memory: 1280Mi
          requests:
            cpu: "1"
            memory: 1280Mi
        ports:
        - containerPort: 1080
dimirtyg commented 6 years ago

In continuation to previous comment, I add here mock server log (scenario is to set expectation once and try to hit endpoint (get) twice

golub@1usmgolub:~/tools/mock-server/kube$ k logs -f plm-mock-9-m8xhf -f

java -Dfile.encoding=UTF-8 -Dmockserver.logLevel=INFO -jar /opt/mockserver/mockserver-netty-jar-with-dependencies.jar -serverPort 1080 -proxyPort 1090

2018-01-25 18:17:53,923 INFO o.m.m.MockServer MockServer started on port: 1080 2018-01-25 18:17:53,966 INFO o.m.p.http.HttpProxy MockServer started on port: 1090 2018-01-25 18:23:07,794 INFO o.m.m.HttpStateHandler creating expectation:

{
  "httpRequest" : {
    "path" : "/some/path2"
  },
  "times" : {
    "remainingTimes" : 1,
    "unlimited" : false
  },
  "timeToLive" : {
    "unlimited" : true
  },
  "httpResponse" : {
    "body" : "some_response_body"
  }
}

2018-01-25 18:23:08,291 INFO o.m.m.HttpStateHandler request:

{
  "method" : "GET",
  "path" : "/some/path2",
  "headers" : {
    "content-length" : [ "0" ],
    "Accept" : [ "application/json" ],
    "User-Agent" : [ "curl/7.49.1" ],
    "Host" : [ "a176448f5fffa11e7ac720a19521a2cc-1910945988.eu-west-1.elb.amazonaws.com:1080" ],
    "Content-Type" : [ "application/json" ]
  },
  "keepAlive" : true,
  "secure" : false
}

matched expectation:

{
  "path" : "/some/path2"
}

2018-01-25 18:23:08,296 INFO o.m.m.HttpStateHandler returning response:

{
  "headers" : {
    "connection" : [ "keep-alive" ]
  },
  "body" : "some_response_body"
}

for request:

{
  "method" : "GET",
  "path" : "/some/path2",
  "headers" : {
    "content-length" : [ "0" ],
    "Accept" : [ "application/json" ],
    "User-Agent" : [ "curl/7.49.1" ],
    "Host" : [ "a176448f5fffa11e7ac720a19521a2cc-1910945988.eu-west-1.elb.amazonaws.com:1080" ],
    "Content-Type" : [ "application/json" ]
  },
  "keepAlive" : true,
  "secure" : false
}

for response action:

{
  "body" : "some_response_body"
}

2018-01-25 18:23:08,633 INFO o.m.m.HttpStateHandler no active expectations when receiving request:

{
  "method" : "GET",
  "path" : "/some/path2",
  "headers" : {
    "content-length" : [ "0" ],
    "Accept" : [ "application/json" ],
    "User-Agent" : [ "curl/7.49.1" ],
    "Host" : [ "a176448f5fffa11e7ac720a19521a2cc-1910945988.eu-west-1.elb.amazonaws.com:1080" ],
    "Content-Type" : [ "application/json" ]
  },
  "keepAlive" : true,
  "secure" : false
}

2018-01-25 18:23:08,772 INFO o.m.m.HttpStateHandler no active expectations when receiving request:

{
  "method" : "GET",
  "path" : "/some/path2",
  "headers" : {
    "content-length" : [ "0" ],
    "Accept" : [ "application/json" ],
    "User-Agent" : [ "curl/7.49.1" ],
    "host" : [ "a176448f5fffa11e7ac720a19521a2cc-1910945988.eu-west-1.elb.amazonaws.com:1080" ],
    "connection" : [ "keep-alive" ],
    "accept-encoding" : [ "gzip,deflate" ],
    "Content-Type" : [ "application/json" ]
  },
  "keepAlive" : true,
  "secure" : false
}

2018-01-25 18:23:08,791 INFO o.m.m.HttpStateHandler no active expectations when receiving request:

{
  "method" : "GET",
  "path" : "/some/path2",
  "headers" : {
    "content-length" : [ "0" ],
    "Accept" : [ "application/json" ],
    "User-Agent" : [ "curl/7.49.1" ],
    "host" : [ "a176448f5fffa11e7ac720a19521a2cc-1910945988.eu-west-1.elb.amazonaws.com:1080" ],
    "connection" : [ "keep-alive" ],
    "accept-encoding" : [ "gzip,deflate" ],
    "Content-Type" : [ "application/json" ]
  },
  "keepAlive" : true,
  "secure" : false
}

2018-01-25 18:23:08,878 INFO o.m.m.HttpStateHandler no active expectations when receiving request:

{
  "method" : "GET",
  "path" : "/some/path2",
  "headers" : {
    "content-length" : [ "0" ],
    "Accept" : [ "application/json" ],
    "User-Agent" : [ "curl/7.49.1" ],
    "host" : [ "a176448f5fffa11e7ac720a19521a2cc-1910945988.eu-west-1.elb.amazonaws.com:1080" ],
    "connection" : [ "keep-alive" ],
    "accept-encoding" : [ "gzip,deflate" ],
    "Content-Type" : [ "application/json" ]
  },
  "keepAlive" : true,
  "secure" : false
}

2018-01-25 18:23:08,966 INFO o.m.m.HttpStateHandler no active expectations when receiving request:

{
  "method" : "GET",
  "path" : "/some/path2",
  "headers" : {
    "content-length" : [ "0" ],
    "Accept" : [ "application/json" ],
    "User-Agent" : [ "curl/7.49.1" ],
    "host" : [ "a176448f5fffa11e7ac720a19521a2cc-1910945988.eu-west-1.elb.amazonaws.com:1080" ],
    "connection" : [ "keep-alive" ],
    "accept-encoding" : [ "gzip,deflate" ],
    "Content-Type" : [ "application/json" ]
  },
  "keepAlive" : true,
  "secure" : false
}

2018-01-25 18:23:08,981 INFO o.m.m.HttpStateHandler no active expectations when receiving request:

{
  "method" : "GET",
  "path" : "/some/path2",
  "headers" : {
    "content-length" : [ "0" ],
    "Accept" : [ "application/json" ],
    "User-Agent" : [ "curl/7.49.1" ],
    "host" : [ "a176448f5fffa11e7ac720a19521a2cc-1910945988.eu-west-1.elb.amazonaws.com:1080" ],
    "connection" : [ "keep-alive" ],
    "accept-encoding" : [ "gzip,deflate" ],
    "Content-Type" : [ "application/json" ]
  },
  "keepAlive" : true,
  "secure" : false
}

2018-01-25 18:23:09,076 INFO o.m.m.HttpStateHandler no active expectations when receiving request:

{
  "method" : "GET",
  "path" : "/some/path2",
  "headers" : {
    "content-length" : [ "0" ],
    "Accept" : [ "application/json" ],
    "User-Agent" : [ "curl/7.49.1" ],
    "host" : [ "a176448f5fffa11e7ac720a19521a2cc-1910945988.eu-west-1.elb.amazonaws.com:1080" ],
    "connection" : [ "keep-alive" ],
    "accept-encoding" : [ "gzip,deflate" ],
    "Content-Type" : [ "application/json" ]
  },
  "keepAlive" : true,
  "secure" : false
}

2018-01-25 18:23:09,171 INFO o.m.m.HttpStateHandler no active expectations when receiving request:

{
  "method" : "GET",
  "path" : "/some/path2",
  "headers" : {
    "content-length" : [ "0" ],
    "Accept" : [ "application/json" ],
    "User-Agent" : [ "curl/7.49.1" ],
    "host" : [ "a176448f5fffa11e7ac720a19521a2cc-1910945988.eu-west-1.elb.amazonaws.com:1080" ],
    "connection" : [ "keep-alive" ],
    "accept-encoding" : [ "gzip,deflate" ],
    "Content-Type" : [ "application/json" ]
  },
  "keepAlive" : true,
  "secure" : false
}

2018-01-25 18:23:09,191 INFO o.m.m.HttpStateHandler no active expectations when receiving request:

{
  "method" : "GET",
  "path" : "/some/path2",
  "headers" : {
    "content-length" : [ "0" ],
    "Accept" : [ "application/json" ],
    "User-Agent" : [ "curl/7.49.1" ],
    "host" : [ "a176448f5fffa11e7ac720a19521a2cc-1910945988.eu-west-1.elb.amazonaws.com:1080" ],
    "connection" : [ "keep-alive" ],
    "accept-encoding" : [ "gzip,deflate" ],
    "Content-Type" : [ "application/json" ]
  },
  "keepAlive" : true,
  "secure" : false
}

2018-01-25 18:23:09,278 INFO o.m.m.HttpStateHandler no active expectations when receiving request:

{
  "method" : "GET",
  "path" : "/some/path2",
  "headers" : {
    "content-length" : [ "0" ],
    "Accept" : [ "application/json" ],
    "User-Agent" : [ "curl/7.49.1" ],
    "host" : [ "a176448f5fffa11e7ac720a19521a2cc-1910945988.eu-west-1.elb.amazonaws.com:1080" ],
    "connection" : [ "keep-alive" ],
    "accept-encoding" : [ "gzip,deflate" ],
    "Content-Type" : [ "application/json" ]
  },
  "keepAlive" : true,
  "secure" : false
}

2018-01-25 18:23:09,293 INFO o.m.m.HttpStateHandler no active expectations when receiving request:

{
  "method" : "GET",
  "path" : "/some/path2",
  "headers" : {
    "content-length" : [ "0" ],
    "Accept" : [ "application/json" ],
    "User-Agent" : [ "curl/7.49.1" ],
    "host" : [ "a176448f5fffa11e7ac720a19521a2cc-1910945988.eu-west-1.elb.amazonaws.com:1080" ],
    "connection" : [ "keep-alive" ],
    "accept-encoding" : [ "gzip,deflate" ],
    "Content-Type" : [ "application/json" ]
  },
  "keepAlive" : true,
  "secure" : false
}

2018-01-25 18:23:09,376 INFO o.m.m.HttpStateHandler no active expectations when receiving request:

{
  "method" : "GET",
  "path" : "/some/path2",
  "headers" : {
    "content-length" : [ "0" ],
    "Accept" : [ "application/json" ],
    "User-Agent" : [ "curl/7.49.1" ],
    "host" : [ "a176448f5fffa11e7ac720a19521a2cc-1910945988.eu-west-1.elb.amazonaws.com:1080" ],
    "connection" : [ "keep-alive" ],
    "accept-encoding" : [ "gzip,deflate" ],
    "Content-Type" : [ "application/json" ]
  },
  "keepAlive" : true,
  "secure" : false
}

2018-01-25 18:23:09,471 INFO o.m.m.HttpStateHandler no active expectations when receiving request:

{
  "method" : "GET",
  "path" : "/some/path2",
  "headers" : {
    "content-length" : [ "0" ],
    "Accept" : [ "application/json" ],
    "User-Agent" : [ "curl/7.49.1" ],
    "host" : [ "a176448f5fffa11e7ac720a19521a2cc-1910945988.eu-west-1.elb.amazonaws.com:1080" ],
    "connection" : [ "keep-alive" ],
    "accept-encoding" : [ "gzip,deflate" ],
    "Content-Type" : [ "application/json" ]
  },
  "keepAlive" : true,
  "secure" : false
}

2018-01-25 18:23:09,570 INFO o.m.m.HttpStateHandler no active expectations when receiving request:

{
  "method" : "GET",
  "path" : "/some/path2",
  "headers" : {
    "content-length" : [ "0" ],
    "Accept" : [ "application/json" ],
    "User-Agent" : [ "curl/7.49.1" ],
    "host" : [ "a176448f5fffa11e7ac720a19521a2cc-1910945988.eu-west-1.elb.amazonaws.com:1080" ],
    "connection" : [ "keep-alive" ],
    "accept-encoding" : [ "gzip,deflate" ],
    "Content-Type" : [ "application/json" ]
  },
  "keepAlive" : true,
  "secure" : false
}

2018-01-25 18:23:09,585 INFO o.m.m.HttpStateHandler no active expectations when receiving request:

{
  "method" : "GET",
  "path" : "/some/path2",
  "headers" : {
    "content-length" : [ "0" ],
    "Accept" : [ "application/json" ],
    "User-Agent" : [ "curl/7.49.1" ],
    "host" : [ "a176448f5fffa11e7ac720a19521a2cc-1910945988.eu-west-1.elb.amazonaws.com:1080" ],
    "connection" : [ "keep-alive" ],
    "accept-encoding" : [ "gzip,deflate" ],
    "Content-Type" : [ "application/json" ]
  },
  "keepAlive" : true,
  "secure" : false
}

2018-01-25 18:23:09,680 INFO o.m.m.HttpStateHandler no active expectations when receiving request:

{
  "method" : "GET",
  "path" : "/some/path2",
  "headers" : {
    "content-length" : [ "0" ],
    "Accept" : [ "application/json" ],
    "User-Agent" : [ "curl/7.49.1" ],
    "host" : [ "a176448f5fffa11e7ac720a19521a2cc-1910945988.eu-west-1.elb.amazonaws.com:1080" ],
    "connection" : [ "keep-alive" ],
    "accept-encoding" : [ "gzip,deflate" ],
    "Content-Type" : [ "application/json" ]
  },
  "keepAlive" : true,
  "secure" : false
}

2018-01-25 18:24:07,868 ERROR o.m.m.HttpStateHandler Exception processing { "method" : "GET", "path" : "/some/path2", "headers" : { "Host" : [ "a176448f5fffa11e7ac720a19521a2cc-1910945988.eu-west-1.elb.amazonaws.com:1080" ], "User-Agent" : [ "curl/7.49.1" ], "Accept" : [ "application/json" ], "Content-Type" : [ "application/json" ], "content-length" : [ "0" ] }, "keepAlive" : true, "secure" : false } java.lang.RuntimeException: Exception while sending request - java.lang.RuntimeException: Channel set as inactive before valid response has been received at org.mockserver.client.netty.NettyHttpClient.sendRequest(NettyHttpClient.java:101) ~[mockserver-netty-jar-with-dependencies.jar:na] at org.mockserver.mock.action.ActionHandler.processAction(ActionHandler.java:111) ~[mockserver-netty-jar-with-dependencies.jar:na] at org.mockserver.mockserver.MockServerHandler.channelRead0(MockServerHandler.java:107) [mockserver-netty-jar-with-dependencies.jar:na] at org.mockserver.mockserver.MockServerHandler.channelRead0(MockServerHandler.java:37) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:108) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:284) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [mockserver-netty-jar-with-dependencies.jar:na] at org.mockserver.unification.PortUnificationHandler.switchToHttp(PortUnificationHandler.java:188) [mockserver-netty-jar-with-dependencies.jar:na] at org.mockserver.unification.PortUnificationHandler.channelRead0(PortUnificationHandler.java:91) [mockserver-netty-jar-with-dependencies.jar:na] at org.mockserver.unification.PortUnificationHandler.channelRead0(PortUnificationHandler.java:37) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1359) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:935) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:138) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:645) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:138) [mockserver-netty-jar-with-dependencies.jar:na] at java.lang.Thread.run(Thread.java:748) [na:1.8.0_151] Caused by: java.util.concurrent.ExecutionException: java.lang.RuntimeException: Channel set as inactive before valid response has been received at com.google.common.util.concurrent.AbstractFuture$Sync.getValue(AbstractFuture.java:299) ~[mockserver-netty-jar-with-dependencies.jar:na] at com.google.common.util.concurrent.AbstractFuture$Sync.get(AbstractFuture.java:272) ~[mockserver-netty-jar-with-dependencies.jar:na] at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:96) ~[mockserver-netty-jar-with-dependencies.jar:na] at org.mockserver.client.netty.NettyHttpClient.sendRequest(NettyHttpClient.java:80) ~[mockserver-netty-jar-with-dependencies.jar:na] ... 51 common frames omitted Caused by: java.lang.RuntimeException: Channel set as inactive before valid response has been received at org.mockserver.client.netty.HttpClientConnectionHandler.updatePromise(HttpClientConnectionHandler.java:19) ~[mockserver-netty-jar-with-dependencies.jar:na] at org.mockserver.client.netty.HttpClientConnectionHandler.channelInactive(HttpClientConnectionHandler.java:25) ~[mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:245) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:231) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:224) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.DefaultChannelPipeline$HeadContext.channelInactive(DefaultChannelPipeline.java:1354) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:245) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:231) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.DefaultChannelPipeline.fireChannelInactive(DefaultChannelPipeline.java:917) [mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.AbstractChannel$AbstractUnsafe$8.run(AbstractChannel.java:822) ~[mockserver-netty-jar-with-dependencies.jar:na] at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163) ~[mockserver-netty-jar-with-dependencies.jar:na] at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:403) ~[mockserver-netty-jar-with-dependencies.jar:na] at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:463) [mockserver-netty-jar-with-dependencies.jar:na] ... 3 common frames omitted

jamesdbloom commented 6 years ago

Problem:

I now understand what the problem is. It is caused by the combining of the proxy and the mocking logic as part of a significant simplification and harmonisation refactoring. Under the hood MockServer attempts to detect if you are using it as a proxy or to mock a request.

Proxy mode is easy to detect for an HTTPS or SOCK proxy due to the fact that the client makes one or more specific requests (such as the HTTP CONNECT request) to indicate it is connecting to a proxy. However for normal HTTP (i.e. not over TLS) it is not easy to detect a request being proxied. The mechanism I am using is to detect if the socket exposed by MockServer is different to the Host header. This works correctly (i.e. locally) except when MockServer is behind a load balancer. For example in AWS this would include an Elastic Load Balancer (ELB), Application Load Balancer (ALB), CloundFront (CDN), Web Application Firewall (WAF) or any other custom load balancer such as Nginx or Apache HTTP. This load balancer / network infrastructure often breaks the automatic detection of whether the request is being proxied because they forward the request to a new socket (ip & port) and potentially don't update the Host header to correspond to the new socket, often not updating the Host header is deliberate for a number of reasons.

Solution:

I think the only sensible solution is to not automatically proxy HTTP requests unless this is explicitly configured. The reason I wanted to avoid this in the first place is that anything that has to manually configured is a source of confusion and misunderstanding, however you valid issue outweighs the potential confusion. I will need to ensure I come up with a configuration approach that tries to reduce any potential confusion.

When:

I will make this change for the next release. The next release will be a major version bump because there have been numerous changes some of which have minor breaking code changes (just some minor renaming of methods so that new functionality can be added). The next release will include a lot of new features such as a UI to see what is happening inside MockServer remotely which should be helpful for you in AWS.

A snapshot version will be ready for you to use in the next few days by using the jamesdbloom/mockserver:mockserver-snapshot docker image. I'll update this issue once that is ready.

dimirtyg commented 6 years ago

Awesome, Thanks you James!

dimirtyg commented 6 years ago

Looking forward to using the snapshot.

jamesdbloom commented 6 years ago

I believe this is now fixed. In the end I didn't need to add a new command line switch or any configuration. Instead I did something more interesting and slightly more complex internally which should save the confusion around an extra command line switch / configuration. I believe I have tested this in the build to the best extent I can and should have covered your use case. However I would be grateful if you could check if the new SNAPSHOT version has resolved the issue. If it has I'll close the issue.

jamesdbloom commented 6 years ago

If you still have a problem please explains as much as possible your AWS setup so I can reproduce it myself to debug any remaining issue. Although currently I do think your issue is resolved, if I've understood the cause correctly.

jamesdbloom commented 6 years ago

I have tested this in Kubernetes and I believe I have resolved all the issues. So I am going to close this issue. Please retest and re-open if you find the issue still exists, but please make sure to use the latest snapshot (i.e. mockserver-snapshot image tag).

dimirtyg commented 6 years ago

Confirmed fixed. Thanks a lot James

dimirtyg commented 6 years ago

Thanks

Confirmed fixed. Thanks a lot James

On Sun, Feb 11, 2018 at 9:50 AM, James D Bloom notifications@github.com wrote:

I have tested this in Kubernetes and I believe I have resolved all the issues. So I am going to close this issue. Please retest and re-open if you find the issue still exists, but please make sure to use the latest snapshot (i.e. mockserver-snapshot image tag).

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jamesdbloom/mockserver/issues/420#issuecomment-364771694, or mute the thread https://github.com/notifications/unsubscribe-auth/AdgJ1WNp8Gj11-vhAA_spJ0HszmIpNRxks5tTyiAgaJpZM4Rqs8S .

DStape commented 6 years ago

I'm hitting the same issue just now with a fairly simple setup.

I have a docker-compose that defines two services, nginx and serviceX. nginx is configured to be a reverse proxy. e.g. the request GET <ip>:<port>/some_resource is sent to nginx and behind the scenes, nginx is rerouting that request to /some_other_url/some_resource.

I guess nginx is running as part of the Kubernetes cluster that @dimirtyg is using.

I no longer see this issue when using jamesdbloom/mockserver:mockserver-snapshot, however the when setting up an expectation the default behaviour seems to have changed - before the remainingTimes field in the times object defaulted to 1, however with the mockserver-snapshot image that's now unlimited... was that change deliberate? And if so, are there any other changes to the defaults in comparison to latest?

Thanks, David

DStape commented 6 years ago

Further to this, the actual root cause to the problem I'm seeing seems to be the value of the Connection field in the HTTP header. According to https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection, this can be either close or keep-alive. Nginx, by default, seems to use HTTP 1.0, therefore the connection value is close.

In my nginx config, I added the line proxy_set_header Connection "keep-alive"; This didn't appear to be enough as the same issue occurs. However, when I also add the line proxy_http_version 1.1; this starts working as I expect.

I don't think HTTP 1.0 originally supported persistent connections, so that's potentially why the Java server is ignoring it when it sees it's an HTTP 1.0 packet - but then it obeys the client's request (nginx) when it's a 1.1 packet.

jimkohl commented 6 years ago

Hi James, Same "channel set as inactive" connecting to Docker Swarm cluster fronted by a BigIP load balancer:

private MockServerClient remoteClient = new MockServerClient("swarm.acme", 443)
remoteClient.reset()     // <== channel set as inactive before ...

A remedy was to add withSecure to sendRequest calls in MockServer code: public String retrieveActiveExpectations(HttpRequest httpRequest, Format format) { HttpResponse httpResponse = sendRequest( request() .withSecure(true) ... .withBody(httpRequest != null ? httpRequestSerializer.serialize(httpRequest) : "", StandardCharsets.UTF_8) ); ....

The session created bypasses the HTTP 1.0 issue and no more exception.
It would be nice if there was a configuration setting that could turn on withSecure for a given client. Would you consider adding that to the ConfigurationProperties object or an addt'l MockServerClient constructor? Thanks, Jim

jamesdbloom commented 5 years ago

@DStape the default changed in HTTP/1.1 so that connection keep alive was on by default, it seems like nginx is closing the connection before returning the response to MockServerClient. The interesting question is why this is happening? Certainly when the MockServer returns a connection keep alive response back to nginx then it keep the connection open for the client so it can receive the response. When you get this error do you get an actual response from MockServer?

@jimkohl I could certainly default the MockServerClient to make calls over TLS because MockServer does port unification and so dynamically adapts to requests being over TLS or in clear text. I guess this may help things because this is causing BigIP not to close the connection so quickly or perhaps just to do TLS tunnelling and therefore lose control over the connection and leave that up to MockServer.

jamesdbloom commented 5 years ago

@DStape and @jimkohl I can't reproduce this with nginx or kubernetes if you are still facing this problem with the latest version, please submit a new bug with the full details of the reverse proxy so I can reproduce the bug.

DStape commented 5 years ago

Hi James,

We've upgraded to 5.4.1 and no longer see the issue previously described. I've also just tried the latest image and it works fine too, so I have no issue with this being closed.