-
Notifications
You must be signed in to change notification settings - Fork 5.6k
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
inputs.http does not set Content-Length header correctly #11034
Comments
Given that the HTTP client is just the standard golang net/http module, pretty unlikely that it's broken and handling payload content length incorrectly. Have tested against other HTTP endpoints and HTTP POSTs work just fine. Took a look in wireshark of http vs http_response and I see that http plugin POSTs data with Transfer-Encoding: chunked, while http_response plugin does not. HTTP payload is formatted correctly for both methods. The reason why is unclear but not unsurprising, as HTTP client config is slightly different between the two plugins. So I'm betting the root cause of your issue here is the API server - it has an incomplete HTTP 1.1 implementation and it doesn't know how to handle chunked requests. |
Thanks for your reply. Can I change the Transfer-Encoding used by the http plugin? Optional HTTP headersheaders = {"Transfer-Encoding" = "gzip"} ? |
Doesn't look like there's a way to change this behaviour in Telegraf config. But I think I've found the cause: I think this NopCloser on the io.reader is causing the http Request to not be able to determine the body's content length: Which in turn causes the http Request client to use chunked transfer encoding. In contast to http_response, which doesn't do this: Don't know anything about io readers/writers and closers, so I'll leave it to Telegraf devs from here. |
Since Telegraf is not explicitly setting this value, can you try this and see what happens? |
Hi @powersj. However the reason for this could still be that the endpoint only accept\assumes "chucked" Encoding with a valid Content-length header attached. |
Thanks for trying that. As @jhychan determined, since we are using a ReadCloser the HTTP request is unable to determine the exact content length.
I believe the use of the @reimda thoughts? |
HTTP spec forbids sending Content-Length if using chunked transfer encoding. They are mutually exclusive - it should be one or the other, never both. A client/server that sends both would be sending an invalid request/response - the server/client would not know how large the payload actually is. So the http module is probably going to replace/strip out those headers it has to manage.
I'd expect Transfer-Encoding to be overridden or stripped out by the http module. The HTTP body contains chunk lengths when using chunked transfers. Path forward:
|
Sorry if I'm dumb here, but my understanding and drilldown of the issue is as follow: My API only accept POST requests with Content-Length header. inputs.http_response works fine and sends the expected headers with the correct "Content-length" of the body in the POST request. inputs.http is unable to calculate the correct Content-length and the POST request is sent without the Content-length header.(Probably chunked?) Summarize: inputs.http plugin does NOT support Content-length headers. Please feel free to comment or correct me as I'm by no means any expert, but here to learn. |
Did some more testing: It's possible to set your custom headers, but if you add "Content-Length" the inputs.http plugin strips it. |
.conf file:
Result at API:
|
The current http input plugin, when a body is specified will produce a NopCloser. I believe this is becuase the gzip compression function returns a closer. However, this means that the HTTP request will not include the content-length. For that to happen the request body must either be a string or bytes reader, or bytes buffer. The primary reason to use a closer over those readers is in the even of a lot of data and trying to stay memory efficient. However, as the input plugin is for sending data over http, the size should generally be small. Therefore, switch to bytes and string readers so that the http requests will always include the content-length. fixes: influxdata#11034
The current http input plugin, when a body is specified, will produce a NopCloser. I believe this is because the gzip compression function returns a closer. However, this means that the HTTP request will not include the content-length. For that to happen, the request body must either be a string or bytes reader or bytes buffer. The primary reason to use a closer over those readers is in the event of a lot of data and trying to stay memory efficient. However, as the input plugin sends little data over http, the size should generally be small. Therefore, switch to bytes and string readers so that the http requests will always include the content length. fixes: influxdata#11034
@Badegakken, what is the target you are trying to hit that requires a content-length? I have put up #11083 that switches from Thanks again! |
@powersj , Thanks a lot, I will try it later today. Endpoint is a third party API running on a VSAT antenna controller. |
Relevant telegraf.conf
Logs from Telegraf
System info
Telegraf: 1.22.2 , Operating System: Debian GNU/Linux 11 (bullseye), Kernel: Linux 5.10.0-8-amd64
Docker
No response
Steps to reproduce
Expected behavior
Reply from API with JSON containing login details.
Actual behavior
Reply is:
Additional info
Trying to pull data from an API that requires the Content-Length header in the POST request.
Tried with similiar .conf file using the HTTP_Response inputs plugin and this works as intended towards the same API endpoint.
.conf file:
Response:
The text was updated successfully, but these errors were encountered: