-
Notifications
You must be signed in to change notification settings - Fork 13.3k
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
Bugfix/esp8266 http client #6176
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MklittleFS is still included in the PR. That's actually a .gitignore bug and I'll put a PR in to fix it.
Please double-check that header parsing, I think you're going to set canreuse to true even on HTTP 1.0 connections.
I have more of a problem with the _reuse flag being set to true in the header file as it will be applied for both HTTP 1.1 and 1.0. To fix that we would probably need to set _reuse to false when useHTTP10() is called and _useHTTP10 is set to true. And set it back to true if _useHTTP10 is set to false. |
@earlephilhower you were right about the header parsing. This is corrected in this commit. @jpboucher the connection is only kept alive if _reuse and _canReuse both are true, At the beginning of HTTPClient::handleHeaderResponse() _canReuse is initialized to !_useHTTP10, and later the response header is checked for 'Connection: Keep-Alive', so this is right |
@Jeroen88 If you look at HTTPClient::sendHeader(const char * type) you will see that the _reuse flag is checked for sending keep-alive. If _reuse is true by default you would be sending Keep-alive in HTTP 1.0 even if you never called setReuse(). You are informing the server that you are reusing the socket even if you are not. This will cause issues. |
@jpboucher I think you are right, I will check this later today and correct it I will check for if(_reuse && !_useHTTP10), agree? |
@Jeroen88 Which line? You could still use what I proposed: set _reuse to false inside useHTTP10() when _useHTTP10 is set to true. And set _reuse back to true if _useHTTP10 is set to false. |
@jpboucher In ::sendHeader() |
@Jeroen88 No, this would not work. You want to send Keep-alive in HTTP 1.0 but only if setReuse(true) was called. To keep it simple, the default value of _reuse should depend on the HTTP version being used. Which is why I think the best course of action is to change it's state inside useHTTP10(). It's alright that the default value in the header file is True since by default we are in HTTP1.1. |
@jpboucher thnx for your insights, I followed your suggestion :) |
@earlephilhower I do not know how to remove it from the PR, can you do that for me? |
@Jeroen88 Sorry for name typo before. I can't edit your repo where the PR actually lives, but it should not be hard for you. I think git rm on it will remove it, then you can repush. You might need to redo get.py if git wants to actually delete the dir. |
@earlephilhower I can't get it done. I pull from the remote master to local master. Git says: everything is up-to-date. I push to my remote branch and then I checkout my bugfix/ESP8266HTTPClient branch. I merge local remote into the bugfix branch.
git status says:
Any suggestions? |
At first glance it seems that your remote bugfix branch evolved independently from your local branch somehow. You should try out git kraken (or any other git GUI) to seek differences between your remote and local branch. Have you tried pulling from you remote bugfix branch before pushing? |
Another nitpick that would probably help the API is to add a lock on the _reuse variable when setReuse() is called. I don't think it's mandatory but I think it would be weird for users to call setReuse() only for the flag to be unexpectedly changed anyways when useHTTP10() is called. |
@jpboucher thnx, with git kraken it was possible to solve the branch conflict :) |
@jpboucher Could you suggest some lines of code? |
I think that too.
You must not follow if you don't agree, because it's your PR.
|
@d-a-v, @dmdt, I get a similar error like @dmdt after a while:
Should this be handled by the client? Or should this be handled by the application? I assume that calling ::end() and then ::begin() will restore the connection, but I did not try it yet... The logging comes from a HTTP/1.1 example with setReuse (false) |
Isn't that fixed with |
@d-a-v Nope, this is with the code that I just committed. At first a lot of responses are correct, the logging I posted is when it goes wrong... |
@d-a-v ::geString() still returns the previously fetched payload. ::clear() should be called earlier in the process? |
There is a missing |
Yes, I do agree :) Missing 'true' added. I think I found another bug, in ::handleHeaderResponse() _canReuse should be initialized to _reuse and not to !_useHTTP10. In this way
works correctly. I lost some work during pushing and pulling. I think I recreated everything, could you confirm? I did test HTTP/1.0 and HTTP/1.1, both with and without reusing the connection, but not the '_canReuse = false'-hack, and everything looks fine. |
@d-a-v What about getting an http code < 0 indicating an error? I am running a test now, waiting for an error, and the call ::end() and ::begin() to restore the connection, to see if this works. I think it should be handled in the .ino, not in the library, do you agree? |
I get no more error with
I think I don't understand the question:
Yes, error handling should be done in sketch, and demonstrated in examples. |
@d-a-v That was my question, error handling should be done in the sketch :) Thanks for the cooperation on this one! |
@d-a-v Shouldn't we keep the default parameter for ::disconnect()? Every call from the library is with parameter now, and keeping the default parameter does not break any sketch. |
I think it will give this PR a faster chance to get merged :) |
@d-a-v Done! |
@d-a-v I think I found another flaw in the ESP8266HTTPClient: ::getString() calls ::writeToStream() and at the end of this last function ::disconnect(true) is called. I think after every call to ::connect() a call to::disconnect() should be made. However, if ::sendRequest() returns an error, my sketch does not make a call to ::getString() (because it tests for a return code < 0) and then ::disconnect() is not called. Also, if the server returns 204, no content, getString() returns an error, because the client has already disconnected, and there is no data available. Both errors can easily be corrected, but lead to the requirement to always call ::getString() (even if you know there is no content or if you e.g. read the result directly using ::getStreamPtr()) because otherwise the connection is not handled properly. I do not like the above solution (although I am running tests on it now) Another option would be to introduce a new function, e.g. ::stop() or any other name that should always be called after finishing reading the response, or require ::disconnect(true) to be called always. But the latter suggests that the client is disconnected while it might be reused... I do not like this solution either. Any ideas? |
@Jeroen88 |
@@ -563,6 +573,7 @@ void HTTPClient::setRedirectLimit(uint16_t limit) | |||
void HTTPClient::useHTTP10(bool useHTTP10) | |||
{ | |||
_useHTTP10 = useHTTP10; | |||
_reuse = !useHTTP10; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this method and ::setReuse()
it is possible to set useHTTP10 = true
and _reuse=true
. That is the user shooting themselves in the foot, which is not a high prio for me.
At some point might want to go back and see if useHTTP10 === !reuse
(I think so after reading the code briefly) and then drop one or the other variable if that's true. But for this PR, I'm OK.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@earlephilhower for HTTP/1.0 the default is not reusing the connection, the default for HTTP/1.1 is reusing. However reusing is allowed also on HTTP/1.0. In this case the client must send a Connection: Keep-Alive request header. The server may respond with a Connection: Keep-Alive in which case the connection can be reused. In HTTP/1.1 the client may send a connection: Keep-Alive header, but this is not obligatory. The connection is supposed to be reused unless the server sends a connection: close response header.
This is exactly what ESP8266HTTPClient does
@Jeroen88 can you open a new issue with MCVE about your last message ? |
@d-a-v I will later this week |
Fix HTTP1.1 persistence issue found by @jpboucher solving issue #6152. With HTTP1.1 default behavior now is to reuse the connection, which is compliant with specs.