-
-
Notifications
You must be signed in to change notification settings - Fork 415
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
Fixed state handling of HTTP client connections #2273
Fixed state handling of HTTP client connections #2273
Conversation
The _conn: TCPConnection was used before it was opened. Added an extra state _ConnConnecting for proper handling. Also fixed _ClientConnection not closing the connection when not work needed to be done by calling _send_pending after having received the body part of the HTTP response.
The server gives full control over the response.
packages/net/http/_test.pony
Outdated
fun ref apply(h: TestHelper) ? => | ||
let urls: Array[URL] = | ||
[ | ||
URL.build( |
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.
testing the connection once one should be enough, right?
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.
It is essential that the request is made more than once.
This is the flow of the old code before the fix:
- be apply is called with payload 1
- apply pushes payload 1 on the _unsent list
- _send_pending is called
- _send_pending tries to cast _conn as TCPConnection and fails, because _conn is None; it calls _new_conn()
- _new_conn creates a new TCPConnection and assigns it to _conn
- be apply returns
- be apply is called with payload 2
- apply pushes the payload on the _unsent list which now contains two payloads
- apply calls _send_pending
- _send_pending send_pending tries to cast _conn as TCPConnection and succeeds, but _conn is not open yet
- _send_pending continues to shift the payloads from the _unsent list and calls request.write, which it thinks succeeds.
- when all the request have been processed _send_pending and apply return and some time after that the be _connected behaviour is called and now _conn is really open and ready for use.
It works when you only send one payload, because _send_pending is called again after be _connected is called and _conn is a connected TCPConnection.
This is the scenario:
- be apply is called with payload 1
- apply pushes payload 1 on the _unsent list
- _send_pending is called
- _send_pending tries to cast _conn as TCPConnection and fails, because _conn is None; it calls _new_conn()
- _new_conn creates a new TCPConnection and assigns it to _conn
- be _connected is called and calls _send_pending
- _send_pending works fine now, because _conn is actually connected.
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.
Totally true. You need to send at least two requests.
But it would suffice to create 1 url, as it is always the same and just use a collections.Range
from 0 to 5 or so to iterate over and send a request on each iteration.
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.
That is true, but in my initial test I sent multiple request to different sites and this code made it easier to perform these tests.
I kept it in because there are more bugs in the http package and I may need it later. But I can take it out if you like.
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.
Just to verify. Will the CI start a new build when I push new commits to the PR branch?
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.
One idea still. Sorry if i seem picky but i did this wrong too many times in the past.
If you bind to port 50000 it might be already taken on someones machine and thus the testsuite might fail although pony is just fine.
My suggestion is to bind to port 0 with the TCPListener
and to get the randomly assigned free port back in the TCPListenNotify.connected
method from TCPListener.local_address().port
. This way you make sure that you will most likely always get a free port and the test suite runs just fine.
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.
Afaik the Ci will build every commit you make to a branch that has a PR open in the ponc repo
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.
Will do that. Good tip. Did not know the feature yet.
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.
I assume that you mean the TCPListenNotify.listening method.
The TCPListener.local_address().port returns a strange value. When I set the port value when creating TCPListener to e.g. 50000, then the port has value 20675, when I set it to 5000 port has value 34835. I have no idea why this is. But I assume it is undesired behaviour.
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.
i sure mean TCPListenNotify.listening
.
sorry for the confusion here.
The port from net.NetAddress
is actually from the OS sockaddr_in
(sockaddr_in6
) structure defined in C. This is an unsigned short (U16
) in network byte order that needs to be transformed to host byte order before using it. I learned that right now, sorry for that. :)
Here you have a playground link that shows this:
http://playground.ponylang.org/?gist=f783b91faedef2715d4a585f59ec4039
looking forward to merge your PR.
@@ -98,7 +99,7 @@ actor _ClientConnection is HTTPSession | |||
if node()? is request then | |||
try (_conn as TCPConnection).dispose() end | |||
_conn = None | |||
node.pop()? | |||
node.>remove().pop()? |
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.
@peterzandbergen would you mind putting spaces around the .>
operator to match the style guide?
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.
will fix it
I must have missed that one. Will fix it and try again.
Peter Zandbergen
Tel: +31 6 460 55 872
linkedIn: peterzandbergen <https://www.linkedin.com/in/peterzandbergen>
…On 11 October 2017 at 21:46, Theo Butler ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In packages/net/http/_client_connection.pony
<#2273 (comment)>:
> @@ -98,7 +99,7 @@ actor _ClientConnection is HTTPSession
if node()? is request then
try (_conn as TCPConnection).dispose() end
_conn = None
- node.pop()?
+ node.>remove().pop()?
@peterzandbergen <https://github.com/peterzandbergen> would you mind
putting spaces around the .> operator to match the style guide?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#2273 (review)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AI2XrraXgATGHsemCTtgEgzoFRpNPUHjks5srRsDgaJpZM4P13k5>
.
|
Well Matthias, it wouldn't.
The old code works well if the client submits only one request to the same
scheme, host and service combination. I can send a small description of
what happened in the old code. I discovered the bug when I sent two
requests to the same web site.
I admit that the number of request I put in is a bit over the top, but
there should be more than one. I was playing chaos monkey.
Cheers
Peter Zandbergen
Tel: +31 6 460 55 872
linkedIn: peterzandbergen <https://www.linkedin.com/in/peterzandbergen>
…On 11 October 2017 at 21:32, Matthias Wahl ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In packages/net/http/_test.pony
<#2273 (comment)>:
> + ha = ha'
+ h = h'
+
+ fun apply(session: HTTPSession): HTTPHandler ref^ =>
+ h.log("_TestHTTPHandlerFactory.apply called")
+ _TestHTTPHandler(ha, h)
+
+class iso _HTTPConnTest is UnitTest
+ var server: (TCPListener | None) = None
+ fun name(): String => "net/http/_HTTPConnection._new_conn"
+ fun label(): String => "conn-fix"
+
+ fun ref apply(h: TestHelper) ? =>
+ let urls: Array[URL] =
+ [
+ URL.build(
testing the connection once one should be enough, right?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#2273 (review)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AI2XrmoOwifqqU2DhmaE_0AgUr4U6LO0ks5srRfCgaJpZM4P13k5>
.
|
- put spaces around .> according to style guide - reduced the number of http requests to 3
packages/net/http/_test.pony
Outdated
try (server as TCPListener).dispose() end | ||
|
||
//////////////////////// | ||
primitive ResponseWriter |
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.
Please also make sure that all test types are private, that is start with underscore, otherwise they are exposed in the stdlib.
Needed to use the name() method of the NetAddress to retrieve the service number.
No worries. Just committed the working version.
Op do 12 okt. 2017 10:21 schreef Matthias Wahl <[email protected]>:
***@***.**** commented on this pull request.
------------------------------
In packages/net/http/_test.pony
<#2273 (comment)>:
> + ha = ha'
+ h = h'
+
+ fun apply(session: HTTPSession): HTTPHandler ref^ =>
+ h.log("_TestHTTPHandlerFactory.apply called")
+ _TestHTTPHandler(ha, h)
+
+class iso _HTTPConnTest is UnitTest
+ var server: (TCPListener | None) = None
+ fun name(): String => "net/http/_HTTPConnection._new_conn"
+ fun label(): String => "conn-fix"
+
+ fun ref apply(h: TestHelper) ? =>
+ let urls: Array[URL] =
+ [
+ URL.build(
i sure mean TCPListenNotify.listening.
sorry for the confusion here.
The port from net.NetAddress is actually from the OS sockaddr_in (
sockaddr_in6) structure defined in C. This is an unsigned short (U16) in
network byte order. I learned that right now, sorry for that. :)
Here you have a playground link that shows this:
http://playground.ponylang.org/?gist=f783b91faedef2715d4a585f59ec4039
looking forward to merge your PR.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#2273 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AI2Xrs2aQ2toZFPBjm_38xK4uJvpofgaks5srcwggaJpZM4P13k5>
.
--
Peter Zandbergen
Tel: +31 6 460 55 872
linkedIn: peterzandbergen <https://www.linkedin.com/in/peterzandbergen>
|
I've cancelled the AppVeyor builds since they were failing after a 1 hour time out. Not really sure what's going on here, maybe some firewall issues with AppVeyor. |
Hi Benoit,
I've noticed it too. The execution stops somewhere in the middle of a test,
which does not seem to be related to my hacking.
Cheers
Peter Zandbergen
Tel: +31 6 460 55 872
linkedIn: peterzandbergen <https://www.linkedin.com/in/peterzandbergen>
…On 12 October 2017 at 16:39, Benoit Vey ***@***.***> wrote:
I've cancelled the AppVeyor builds since they're failing after a 1 hour
time out. Not really sure what's going on here, maybe some firewall issues
with AppVeyor.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#2273 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AI2Xrr212zYVwsmVQCW7L-jDtvHN67K0ks5sriSEgaJpZM4P13k5>
.
|
packages/net/http/_test.pony
Outdated
// "Content-Length: 0" | ||
// "Status: 520 Unknown Error" | ||
// "" | ||
// ] |
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.
What's going on with this commented-out code block?
packages/net/http/_test.pony
Outdated
fun ref tear_down(h: TestHelper) => | ||
try (server as TCPListener).dispose() end | ||
|
||
//////////////////////// |
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.
What's the purpose of this comment line?
Hi Joe,
this can go, I kept it in because I thought I might need it later on to
have different test cases for the _HTTPParser which I believe has errors.
Cheers
Peter Zandbergen
Tel: +31 6 460 55 872
linkedIn: peterzandbergen <https://www.linkedin.com/in/peterzandbergen>
…On 12 October 2017 at 18:11, Joe Eli McIlvain ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In packages/net/http/_test.pony
<#2273 (comment)>:
> + // "Content-Type: text/html; charset=utf-8"
+ "Content-Length: 0"
+ "Status: 200 OK"
+ ""
+ ]
+ // For future use.
+ // fun val error_503(): Array[String val] val^ =>
+ // [ as String val:
+ // "HTTP/1.1 520 Unknown Error"
+ // "Server: pony_fake_server"
+ // // "Date: Wed, 11 Oct 2017 15:16:32 GMT"
+ // // "Content-Type: text/html; charset=utf-8"
+ // "Content-Length: 0"
+ // "Status: 520 Unknown Error"
+ // ""
+ // ]
What's going on with this commented-out code block?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#2273 (review)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AI2XrqPEZ40cJndKB-sOCW7-glDHUy-iks5srjokgaJpZM4P13k5>
.
|
Just a separator. Will fix it.
Peter Zandbergen
Tel: +31 6 460 55 872
linkedIn: peterzandbergen <https://www.linkedin.com/in/peterzandbergen>
…On 12 October 2017 at 18:11, Joe Eli McIlvain ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In packages/net/http/_test.pony
<#2273 (comment)>:
> + h,
+ {(p: String val) =>
+ worker.listening(p)
+ }
+ ),
+ "", // all interfaces
+ "0" // service
+ )
+
+ // Start a long test for 2 seconds.
+ h.long_test(10_000_000_000)
+
+ fun ref tear_down(h: TestHelper) =>
+ try (server as TCPListener).dispose() end
+
+////////////////////////
What's the purpose of this comment line?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#2273 (review)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AI2XrjkyiUebQyzEoFfkERpEQiNmPyMkks5srjo0gaJpZM4P13k5>
.
|
Support classes for the client are prefixed with _HTTPConnTest. Fake server uses less classes, preventing name clashes.
This is most likely not a firewall issue on appveyor. There are also other tests in the net package that create a Maybe it is the I would nonetheless suggest the decrease the test timeout significantly, so timeouts are much earlier detectable. |
The timeout I use is 10 seconds. What do you advise?
Op za 14 okt. 2017 00:56 schreef Matthias Wahl <[email protected]>:
This is most likely not a firewall issue on appveyor. There are also other
tests in the net package that create a TCPListener e.g.
https://github.com/ponylang/ponyc/blob/master/packages/net/_test.pony#L159
Maybe it is the TestHelper.dispose_when_done call that keeps resources
hanging?
Just a wild guess tbh. But this is the only difference i can spot.
I would nonetheless suggest the decrease the test timeout significantly,
so timeouts are much earlier detectable.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#2273 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AI2XrlRA_iR1E1c-mYAEALDd0KQqQ-8Qks5sr-qBgaJpZM4P13k5>
.
--
Peter Zandbergen
Tel: +31 6 460 55 872
linkedIn: peterzandbergen <https://www.linkedin.com/in/peterzandbergen>
|
Gosh, this is getting out of hand. Now i mistook the timings for milliseconds. I always do tbh. I also meant that you should call TestHelper.dispose_when_done(...) for the same resources the mentioned test from the net package calls it. I.e. TCPListener |
Appveyor times out on the test and the suspicion is that the http serve for generating the fixed response should be closed using dispose_when_done. This works for the test for TCPConnection.
I restartet 2 test runs on travisci on OSX that seem to be unrelated but concerning. |
Hi Matthias,
I was wondering what is special about my test code. I thought that it was
allowed to instantiate actors in a unit test. Is there anything strange in
my code that you can spot?
Op ma 16 okt. 2017 20:22 schreef Matthias Wahl <[email protected]>:
I restartet 2 test runs on OSX that seem to be unrelated but concerning.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#2273 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AI2XrplkYWjff9baCITfL45DQhRtzyXIks5ss57cgaJpZM4P13k5>
.
--
Peter Zandbergen
Tel: +31 6 460 55 872
linkedIn: peterzandbergen <https://www.linkedin.com/in/peterzandbergen>
|
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.
@peterzandbergen i am not 100% sure what the issue is with those tests. I hope the comments i made might help. it is most likely a socket not properly closed as the appveyor builds seem to be hanging after the test has been completed successfully.
packages/net/http/_test.pony
Outdated
h = h' | ||
|
||
fun apply(session: HTTPSession): HTTPHandler ref^ => | ||
h.log("_HTTPConnTestHandlerFactory.apply called") |
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.
You could also call TestHelper.dispose_when_done(session)
here instead of adding a dispose()
to the HTTPClient
, although i think HTTPClient
should have such a method. But rather in another PR.
packages/net/http/_test.pony
Outdated
None | ||
|
||
fun ref connect_failed(conn: TCPConnection ref) => | ||
None |
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.
i personally like the approach of https://github.com/ponylang/ponyc/blob/master/packages/net/_test.pony#L202 where multiple TestHelper.expect_action
calls are made for each stage towards completion of the test. At points like this, where the test failed, a TestHelper.fail_action
call can greatly help pinpointing possible issues.
packages/net/http/_test.pony
Outdated
// Write the response. | ||
if start then | ||
for r in response.values() do | ||
conn.write(r + "\n") |
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.
if i am correct, HTTP headers are separated by \r\n
.
packages/net/http/_test.pony
Outdated
try | ||
(client as HTTPClient iso)(consume payload, hf)? | ||
end | ||
// match client |
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.
remove
packages/net/http/_test.pony
Outdated
end // while | ||
true | ||
|
||
fun ref accepted(conn: TCPConnection ref) => |
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.
maybe a TestHelper.dispose_when_done(conn)
on this side helps as well.
This one is blocked by #2322 |
Windows tests are fixed by #2325 |
Thanks for fixing the Windows issue. Does this mean that I can push my pull request again? |
The test passes with the fix that Gordon made for the TCPConnection. So after his pull request #2325 has been accepted I will push my fix again for testing on CI. |
#2325 has been merged. |
One of the iOS tests in Travis failed because bintray get failed. Will bump a new version this evening to try again. |
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.
Finally! :)
Just some few final-cleanup remarks.
Great stuff!
@@ -178,6 +180,7 @@ actor _ClientConnection is HTTPSession | |||
`_chunk`. This is passed on to the front end. | |||
""" | |||
_app_handler.finished() | |||
_send_pending() |
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.
could you explain why this call is here?
I cannot see how this is related to the _conn state handling.
Isn't this method is called by the HTTPParser when a chunked response body has been fully received?
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.
Hi Matthias,
this allows the state machine to handle the situation that no both pending and unsent requests are empty. If this line is removed then the connection will not close the connection if no work has to be done, will not dispose the connection and waits and waits .... I realize that this is an extra fix but needed it to get the tests working and not timing out.
@@ -189,9 +192,11 @@ actor _ClientConnection is HTTPSession | |||
""" | |||
Close the connection from the client end. | |||
""" | |||
_cancel_all() |
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.
The behaviour of cancelling all pending requests should be documented in the docstring.
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.
Will add it.
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.
Hi Matthias, I processed your remarks and pushed a new commit.
packages/net/http/_test.pony
Outdated
@@ -25,6 +29,8 @@ actor Main is TestList | |||
test(_Valid) | |||
test(_ToStringFun) | |||
|
|||
// Disabled to check if this causes the appveyor block. |
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.
remove
packages/net/http/client.pony
Outdated
@@ -53,6 +53,11 @@ class HTTPClient | |||
let valrequest: Payload val = consume request | |||
session(valrequest) | |||
valrequest | |||
|
|||
fun dispose() => |
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.
please clear the _sessions
map as well and add a docstring describing what happens here.
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.
Will do.
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.
Done
packages/net/http/_test.pony
Outdated
end // try | ||
|
||
be dispose() => | ||
// try |
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.
do you want to uncomment those lines?
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.
Will do.
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.
I have to take it back. This was something that I put in to fix the problem on windows. Because it is not needed I will remove it from the code. As you mentioned earlier only one fix per pull request.
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.
This code is not necessary. I put it in hoping it would fix the problem on Windows.
I will take it out.
I took the freedom to change the title to be more meaningful when appearing in the changelog as "Fixed" entry. |
Processed the remarks from Matthias (thanks) - Added docstrings - cleared the _sessions in HTTPClient.dispose()
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.
Approved.
Great. Thanks
Op ma 20 nov. 2017 22:54 schreef Matthias Wahl <[email protected]>:
***@***.**** approved this pull request.
Approved.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#2273 (review)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AI2Xrs09ydziFxQAg5xQv4-tz0rbIXtUks5s4fURgaJpZM4P13k5>
.
--
Peter Zandbergen
Tel: +31 6 460 55 872
linkedIn: peterzandbergen <https://www.linkedin.com/in/peterzandbergen>
|
@mfelsche - I haven't reviewed this, but if you feel comfortable merging it, feel free to go ahead! |
@jemc as far as i can see, this is totally fine. If it is not and i didnt see it, i take full responsibility and buy a round for everybody involved |
I will share the round with you. No worries. |
The _conn: TCPConnection was used before it was opened.
Added an extra state _ConnConnecting for proper handling.
Also fixed _ClientConnection not closing the connection
when not work needed to be done by calling _send_pending
after having received the body part of the HTTP response.
Added one trick pony http server for testing