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

POST doesn't close the connection when 204 response used #80

Open
billmote opened this issue Aug 14, 2020 · 6 comments
Open

POST doesn't close the connection when 204 response used #80

billmote opened this issue Aug 14, 2020 · 6 comments

Comments

@billmote
Copy link

billmote commented Aug 14, 2020

What you did:

Created a POST route
{ "id": "8e54c04a-21fd-4cb3-b8de-1aa5a9ef988e", "route": "/events", "httpMethod": "POST", "statusCode": "204", "delay": "0", "payload": { "success": true }, "headers": [ { "id": "6ffb195d-c434-46da-a08c-52090415c949", "header": "Retry-After", "value": "60" } ], "disabled": false }
that responds with a HTTP 204 with a simple body of { success: true } and posted:

curl --request POST '169.254.241.176:3000/events' --header 'Content-Type: application/json' --data-raw '[{"eventId":"fbf1de19-8629-45d3-ad0f-34b8e17d594f","sessionId":"07726e3d-68ed-49a2-bb37-d1372e941191","dateTime":"2020-08-14T01:45:44.975Z","eventType":"App Launched","category":"engagement","latitude":40.4543,"longitude":41.4563},{"eventId":"37314774-d52b-4219-b5c4-e3b2c14aeda0","sessionId":"48830e55-33b2-4a8e-b5c7-710b85b44bf5","dateTime":"2020-08-14T01:56:53.220Z","eventType":"view cart","category":"engagement","latitude":40.4543,"longitude":41.4563,"sku":"abc123","price":10.95},{"eventId":"6c8a2370-0fb0-4c47-8914-11a8e2ffe47f","sessionId":"48830e55-33b2-4a8e-b5c7-710b85b44bf5","dateTime":"2020-08-14T01:57:23.341Z","eventType":"App Launched","category","engagement","latitude":40.4543,"longitude":41.4563}]'

What happened:

The body isn't delivered for ~90 seconds -- my connection timeout on the client is set to 30 seconds.

Problem description:

Because it should immediately respond and close the connection?

Suggested solution:

Changing nothing other than the response code back to HTTP 200 fixes the problem (the route responds instantaneously), but I would like to emulate several of the available responses, and I specifically need the 204 response for this POST :)

@billmote billmote changed the title POST doesn't close the connection POST doesn't close the connection when 204 response used Aug 14, 2020
@wohlben
Copy link
Contributor

wohlben commented Aug 16, 2020

Hey @billmote, i'm not the maintainer but just stumbled upon this issue.

while I'd agree that a timeout is suboptimal in this situation, your desired behaviour is kinda confusing as well.

204 is explicitly for situations where you do not have a body.

There is no content to send for this request, but the headers may be useful. The user-agent may update its cached headers for this resource with the new ones.

you're likely suffering from apples decision how to treat these invalid requests.

Apple Safari rejects any such data. Google Chrome and Microsoft Edge discard up to four invalid bytes preceding a valid response. Firefox tolerates in excess of a kilobyte of invalid data preceding a valid response.

you should use another status code if you wish to respond with a body, for example 200 OK,

@billmote
Copy link
Author

Interesting @wohlben. I will raise that with the people writing the endpoint. 204 shouldn't be an issue though (ref. https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/204). It just seems odd that it holds the connection open for a 204 and not a 200. In both cases the work is "done."

@wohlben
Copy link
Contributor

wohlben commented Aug 16, 2020

eh, yes. thats exactly the documentation i linked earlier, and the source of my quotes as well.

for what its worth: i wasn't able to reproduce your timeout issue on my end. though mockIt never responded with a body either (despite having put that {"success": true} in there), only with the explizit status code, which is 204 No Content

$ curl -X POST localhost:3000 -vs
* Rebuilt URL to: localhost:3000/
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 3000 (#0)
> POST / HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.60.0
> Accept: */*
>
< HTTP/1.1 204 No Content
< Access-Control-Allow-Origin: *
< x-api-key: testing123
< Content-Type: application/json; charset=utf-8
< Content-Length: 16
< ETag: W/"10-oV4hJxRVSENxc/wX8+mA4/Pe4tA"
< Date: Sun, 16 Aug 2020 19:17:28 GMT
< Connection: keep-alive
<
* Connection #0 to host localhost left intact

(same with your example request as well)

curl -vs --request POST 'localhost:3000' --header 'Content-Type: application/json' --data-raw '[{"eventId":"fbf1de19-8629-45d3-ad0f-34b8e17d594f","sessionId":"07726e3d-68ed-49a2-bb37-d1372e941191","dateTime":"2020-08-14T01:45:44.975Z","eventType":"App Launched","category":"engagement","latitude":40.4543,"longitude":41.4563},{"eventId":"37314774-d52b-4219-b5c4-e3b2c14aeda0","sessionId":"48830e55-33b2-4a8e-b5c7-710b85b44bf5","dateTime":"2020-08-14T01:56:53.220Z","eventType":"view cart","category":"engagement","latitude":40.4543,"longitude":41.4563,"sku":"abc123","price":10.95},{"eventId":"6c8a2370-0fb0-4c47-8914-11a8e2ffe47f","sessionId":"48830e55-33b2-4a8e-b5c7-710b85b44bf5","dateTime":"2020-08-14T01:57:23.341Z","eventType":"App Launched","category","engagement","latitude":40.4543,"longitude":41.4563}]'
* Rebuilt URL to: localhost:3000/
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 3000 (#0)
> POST / HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.60.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 717
>
} [717 bytes data]
* upload completely sent off: 717 out of 717 bytes
< HTTP/1.1 204 No Content
< Access-Control-Allow-Origin: *
< x-api-key: testing123
< Content-Type: application/json; charset=utf-8
< Content-Length: 16
< ETag: W/"10-oV4hJxRVSENxc/wX8+mA4/Pe4tA"
< Date: Sun, 16 Aug 2020 19:32:08 GMT
< Connection: keep-alive
<
* Connection #0 to host localhost left intact

and finally:

https://tools.ietf.org/html/rfc7231#section-6.3.5

A 204 response is terminated by the first empty line after the header fields because it cannot contain a message body.

/final edit:
there is an empty line transmitted, and the connection stays as keep-alive, so it is not according to specc, that seems to be true :)
though it is a pretty 'minor' thing

"Connection #0 to host (nil) left intact" means that although the transfer is over, the TCP session itself is still open (i.e no FIN/ACK exchanges have been made), allowing you to keep reusing the same TCP connection for multiple transfers (which could be useful if you don't want to sacrifice time on opening a new TCP connection).

@billmote
Copy link
Author

I worked around the issue by adding a byteCount check before calling readAll(), which is what was getting hung up on the empty response. End of the day, makes my networking stack more resilient. Still talking through it with the service team, but here's my current config if you're interested:

{ "id": "8e54c04a-21fd-4cb3-b8de-1aa5a9ef988e", "route": "/events", "httpMethod": "POST", "statusCode": "204", "delay": "500", "payload": {}, "headers": [ { "id": "6ffb195d-c434-46da-a08c-52090415c949", "header": "Retry-After", "value": "5" } ], "disabled": false }

@boyney123
Copy link
Owner

@billmote wonder if it's worth adding this to the docs? What do you think?

Sounds like you got a work around, are you happy for me to close this issue?

@billmote
Copy link
Author

billmote commented Nov 24, 2020 via email

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

No branches or pull requests

3 participants