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

Mock Server fails to handle JSON body correctly #532

Closed dudehook closed 5 years ago

dudehook commented 5 years ago

I'm running the current public Docker image of Mock Server.

When I send a request with the following:

curl -v -X POST -d @new.json --header "Content-Type: text/plain" http://localhost:1080/v1/actionexecutions

And having the following new.json file:

{
        "action": "CreateProject",
        "parameters": {
                "param1": "yo",
                "param2": "boy"
        },
        "final": "true"
}

I get the following exception in Mock Server:

2018-09-13 22:09:38,069 ERROR o.m.m.HttpStateHandler Exception processing {
  "method" : "POST",
  "path" : "/v1/actionexecutions",
  "headers" : {
    "Host" : [ "localhost:1080" ],
    "User-Agent" : [ "curl/7.54.0" ],
    "Accept" : [ "*/*" ],
    "Content-Type" : [ "text/plain" ],
    "Content-Length" : [ "98" ]
  },
  "keepAlive" : true,
  "secure" : false,
  "body" : {
    "type" : "STRING",
    "string" : "{\t\"action\": \"CreateProject\",\t\"parameters\": {\t\t\"param1\": 'yo',\t\t\"param2\": 'boy'\t},\t\"final\": \"true\"}",
    "contentType" : "text/plain; charset=utf-8"
  }
}
java.lang.RuntimeException: Unexpected token: "VALUE_STRING" id: "6" text: "yo
    at org.mockserver.client.serialization.deserializers.collections.KeysToMultiValuesDeserializer.deserializeObject(KeysToMultiValuesDeserializer.java:56) ~[mockserver-netty-jar-with-dependencies.jar:na]
    at org.mockserver.client.serialization.deserializers.collections.KeysToMultiValuesDeserializer.deserialize(KeysToMultiValuesDeserializer.java:35) ~[mockserver-netty-jar-with-dependencies.jar:na]
    at org.mockserver.client.serialization.deserializers.collections.KeysToMultiValuesDeserializer.deserialize(KeysToMultiValuesDeserializer.java:22) ~[mockserver-netty-jar-with-dependencies.jar:na]
    at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:3972) ~[mockserver-netty-jar-with-dependencies.jar:na]
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2264) ~[mockserver-netty-jar-with-dependencies.jar:na]
    at com.fasterxml.jackson.core.JsonParser.readValueAs(JsonParser.java:1723) ~[mockserver-netty-jar-with-dependencies.jar:na]
    at org.mockserver.client.serialization.deserializers.body.BodyDTODeserializer.deserialize(BodyDTODeserializer.java:128) ~[mockserver-netty-jar-with-dependencies.jar:na]
    at org.mockserver.client.serialization.deserializers.body.BodyDTODeserializer.deserialize(BodyDTODeserializer.java:32) ~[mockserver-netty-jar-with-dependencies.jar:na]
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001) ~[mockserver-netty-jar-with-dependencies.jar:na]
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2992) ~[mockserver-netty-jar-with-dependencies.jar:na]
    at org.mockserver.matchers.HttpRequestMatcher.matches(HttpRequestMatcher.java:182) ~[mockserver-netty-jar-with-dependencies.jar:na]
    at org.mockserver.matchers.HttpRequestMatcher.matches(HttpRequestMatcher.java:163) ~[mockserver-netty-jar-with-dependencies.jar:na]
    at org.mockserver.mock.MockServerMatcher.firstMatchingExpectation(MockServerMatcher.java:43) ~[mockserver-netty-jar-with-dependencies.jar:na]
    at org.mockserver.mock.HttpStateHandler.firstMatchingExpectation(HttpStateHandler.java:111) ~[mockserver-netty-jar-with-dependencies.jar:na]
    at org.mockserver.mock.action.ActionHandler.processAction(ActionHandler.java:58) ~[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]
....

If I have no expectations in the server (i.e. a fresh startup), then the request simply causes a 404 response.

If I have any expectations, even if they do not match the path of the request or any other part of the request, I see the exception above.

It doesn't matter what Content-Type I provide in the request.

However, if I remove the quotes from around the values in the "parameters" object, it works:

{
    "action": "CreateProject",
    "parameters": {
        "param1": yo,
        "param2": boy
    },
    "final": "true"
}

"Works" as in there is no exception and a matching action will trigger:

mockServerClient('localhost', 1080)
    .mockWithCallback(
        {
            'path': '/v1/actionexecutions',
        },
        callback,
        {
            'remainingTimes': 1,
            'unlimited': true
        }
    )
    .then(
        function () {
            console.log('expectation created');
        },
        function (error) {
            console.log(error);
        }
    );

This expectation, running in Node, does trigger and the callback is called. However, in the callback code I have the following:

        var obj = JSON.parse(request.body.string);

This code causes the following problem parsing the JSON body without the quotes:

{ method: 'POST',
  path: '/v1/actionexecutions',
  headers:
   { Host: [ 'localhost:1080' ],
     'User-Agent': [ 'curl/7.54.0' ],
     Accept: [ '*/*' ],
     'Content-Type': [ 'text/plain' ],
     'Content-Length': [ '94' ] },
  keepAlive: true,
  secure: false,
  body:
   { type: 'STRING',
     string:
      '{\t"action": "CreateProject",\t"parameters": {\t\t"param1": yo,\t\t"param2": boy\t},\t"final": "true"}',
     contentType: 'text/plain; charset=utf-8' } }
undefined:1
{   "action": "CreateProject",  "parameters": {     "param1": yo,       "param2": boy   },  "final": "true"}
                                                              ^

SyntaxError: Unexpected token y in JSON at position 56
    at JSON.parse (<anonymous>)
    at callback (/Users/dhooker/work/felix-compose/mocking/test.js:11:17)
    at /Users/dhooker/work/felix-compose/mocking/node_modules/mockserver-client/mockServerClient.js:292:55
    at WebSocketConnection.<anonymous> (/Users/dhooker/work/felix-compose/mocking/node_modules/mockserver-client/webSocketClient.js:40:44)
    at WebSocketConnection.emit (events.js:182:13)
    at WebSocketConnection.processFrame (/Users/dhooker/work/felix-compose/mocking/node_modules/websocket/lib/WebSocketConnection.js:552:26)
    at /Users/dhooker/work/felix-compose/mocking/node_modules/websocket/lib/WebSocketConnection.js:321:40
    at process._tickCallback (internal/process/next_tick.js:61:11)

So... with quotes causes Mock Server to fail... without quotes causes Node to fail.

What's going on here?

jamesdbloom commented 5 years ago

This has been fixed in 5.4.1, please retry using that version and re-open issue if you feel it has not been solved.