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

Curl hangs when Header "Expect:100-continue" is set on POST > 1024 bytes #273

Closed
runabol opened this issue Apr 10, 2018 · 14 comments
Closed

Comments

@runabol
Copy link

runabol commented Apr 10, 2018

I'm using Spring Cloud Gateway Finchley.M9.

I noticed that when I proxy a large POST the gateway times out:

$ curl -X POST -H "Content-Type:application/json" -d '[{ "id": "0001", "type": "donut", "name": "Cake", "ppu": 0.55, "batters": { "batter": [{ "id": "1001", "type": "Regular" }, { "id": "1002", "type": "Chocolate" }, { "id": "1003", "type": "Blueberry" }, { "id": "1004", "type": "Devils Food" } ] }, "topping": [{ "id": "5001", "type": "None" }, { "id": "5002", "type": "Glazed" }, { "id": "5005", "type": "Sugar" }, { "id": "5007", "type": "Powdered Sugar" }, { "id": "5006", "type": "Chocolate with Sprinkles" }, { "id": "5003", "type": "Chocolate" }, { "id": "5004", "type": "Maple" } ] }, { "id": "0002", "type": "donut", "name": "Raised", "ppu": 0.55, "batters": { "batter": [{ "id": "1001", "type": "Regular" }] }, "topping": [{ "id": "5001", "type": "None" }, { "id": "5002", "type": "Glazed" }, { "id": "5005", "type": "Sugar" }, { "id": "5003", "type": "Chocolate" }, { "id": "5004", "type": "Maple" } ] }, { "id": "0003", "type": "donut", "name": "Old Fashioned", "ppu": 0.55, "batters": { "batter": [{ "id": "1001", "type": "Regular" }, { "id": "1002", "type": "Chocolate" } ] }, "topping": [{ "id": "5001", "type": "None" }, { "id": "5002", "type": "Glazed" }, { "id": "5003", "type": "Chocolate" }, { "id": "5004", "type": "Maple" } ] } ]' https://my.service.name.behind.the.gateway/my/path

curl: (52) Empty reply from server

This does not happen with smaller body payloads:

$ curl -X POST -H "Content-Type:application/json" -d '[{ "id": "0001", "type": "donut", "name": "Cake", "ppu": 0.55 }, { "id": "0002", "type": "donut", "name": "Raised", "ppu": 0.55, "batters": { "batter": [{ "id": "1001", "type": "Regular" }] }, "topping": [{ "id": "5001", "type": "None" }, { "id": "5002", "type": "Glazed" }, { "id": "5005", "type": "Sugar" }, { "id": "5003", "type": "Chocolate" }, { "id": "5004", "type": "Maple" } ] }, { "id": "0003", "type": "donut", "name": "Old Fashioned", "ppu": 0.55 } ]' https://my.service.name.behind.the.gateway/my/path

{
  "timestamp": "2018-04-10T20:46:45Z",
  "status": 404,
  "error": "Not Found",
  "message": "No message available",
  "path": "/my/path"
}
@spencergibb
Copy link
Member

What version?

Can you tell me how long?

Are you using hystrix?

@runabol
Copy link
Author

runabol commented Apr 10, 2018

Finchley.M9

real    0m59.307s
user    0m0.017s
sys     0m0.014s

Not using Hystrix.

@spencergibb
Copy link
Member

spencergibb commented Apr 10, 2018

Works fine if I use httpie.org

http POST :8080/post Host:www.myhost.org @test.json 

These are the headers set by httpie

Accept: application/json, */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 1518
Content-Type: application/json
Host: www.myhost.org
User-Agent: HTTPie/0.9.8

something to do with curl and reactor and/or netty? @smaldini

@runabol
Copy link
Author

runabol commented Apr 11, 2018

I think that I found the culprit.

Add the Expect:100-continue header to your httpie request. curl adds that header automatically on a payload that is greater than 1024 bytes.

Ref: https://gms.tf/when-curl-sends-100-continue.html

@spencergibb spencergibb changed the title Timeout on large POST Curl hangs when Header "Expect:100-continue" is set on POST > 1024 bytes Apr 11, 2018
@runabol
Copy link
Author

runabol commented Jun 20, 2018

Just tried it again today with Finchley.RELEASE and I wasn't able to reproduce the issue.

@spencergibb
Copy link
Member

thanks for the feedback @creactiviti!

@dan-nawrocki
Copy link

dan-nawrocki commented Jul 8, 2018

This appears to be back for me. I think the regression is caused by 2816605. I believe it disappeared in Finchley.RELEASE because there is no Content-Type for a HTTP 100 response, triggering a NullPointerException that somehow caused both the HTTP 100 response and the target HTTP response to be returned back to curl (?).

I don't know much about spring reactive, but my naive guess from debugging is that spring-cloud-gateway is responding to curl with the HTTP 100 response, and not forwarding the actual response from the target. Does spring-cloud-gateway assume that each request will receive a single response from the target?

I can get curl to work by disabling the 100-Continue feature with -H 'Expect:'.

Edit: @spencergibb any ideas?

@runabol
Copy link
Author

runabol commented Jul 17, 2018

I was able to reproduce and find a workaround to the issue mentioned by @dan-nawrocki.

It seems like the issue was resolved by the netty team: reactor/reactor-netty#293 but for some reason the Expect header still gets forwarded to the target.

The target as a result returns a 100 Continue (as it should) which results in a NullPointerException on NettyRoutingFilter:117 as it's missing a Content-Type on the response:

exchange.getAttributes().put("original_response_content_type", headers.getContentType());

As a workaround I was able to prevent Spring Cloud Gateway from forwarding the Expect header by adding the following to my route:

.filters((t)->t.removeRequestHeader("Expect"))

@spencergibb
Copy link
Member

The NPE has been fixed in snapshots

@Odyseja
Copy link

Odyseja commented Aug 1, 2018

Hi, in 2.0.2.BUILD-SNAPSHOT problem still occurs.
There is no NPE now, but curl still hangs when request body is too big.

@spencergibb
Copy link
Member

@Odyseja what version of spring boot and reactor-netty are you using? The fix is in reactor-netty 0.7.5

@Odyseja
Copy link

Odyseja commented Aug 2, 2018

Spring boot's version is 2.0.3.RELEASE and reactor-netty's version is 0.7.8.RELEASE

@jinchaoxiang
Copy link

me too

@Allen57
Copy link

Allen57 commented Nov 12, 2018

Same here with Spring boot 2.0.6.RELEASE and reactor-netty 0.7.10.RELEASE.
Adding a filter to remove the 'Expect' header (as suggested by @creactiviti) solved the issue for me.

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

6 participants