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

Network.TLS.IO: Return errors as Left #224

Closed
wants to merge 1 commit into from

Conversation

erikd
Copy link
Contributor

@erikd erikd commented Apr 28, 2017

Previously these were thrown as exceptions even though the error
types were correct to return then as a Left.

Closes: #220

@erikd
Copy link
Contributor Author

erikd commented Apr 28, 2017

There is no API change here, but two things that were thown as exceptions from

recvPacket :: MonadIO m => Context -> m (Either TLSError Packet)

namely Error_EOF and Error_Packet are now returned as Left, because both of those constructors were already part of the TLSError type

@ocheron
Copy link
Contributor

ocheron commented Apr 28, 2017

Have you checked if the exceptions are rethrown downstream?
Because we may have code reacting on them.

@erikd
Copy link
Contributor Author

erikd commented Apr 28, 2017

@ocheron "downstream"? You mean in hs-tls or on packages that depend on it?

@ocheron
Copy link
Contributor

ocheron commented Apr 28, 2017

Could be anything actually, but first hs-tls yes.
There's code detecting Error_EOF in TLS.Network.Core, so we'll need to test connection termination carefully.

@kazu-yamamoto
Copy link
Collaborator

Does this mean that contextRecv in readExact should be protected with catch or something?

@erikd
Copy link
Contributor Author

erikd commented May 1, 2017

I need to look at this more carefully. Will do so some time this week.

@ocheron
Copy link
Contributor

ocheron commented May 1, 2017

Here's my full review after checking the code path in more details.

What happens in your scenario at https://github.com/erikd-ambiata/test-https-client-resource-vanished/ is that when you kill one end of the connection, at the other end readExact generates Error_EOF or Error_Packet.

setEOF is called from readExact because we can distinguish there an end-of-stream Error_Packet from other Error_Packet exceptions raised by disengageRecord. I don't think it's safe to remove the setEOF call.

Also exception Error_EOF is caught with safeHandleError_EOF, so that recvData returns an empty bytestring. Moving away from exceptions is good, but the behaviour should not change.

I'm not against wrapping an end-of-stream Error_Packet inside a Terminated exception. I have no idea if it's possible to recover from Error_Packet exceptions coming from disengageRecord, so I would prefer not to change that part.

@erikd erikd force-pushed the topic/error-packet-left branch from f8d95e8 to f6e88db Compare May 4, 2017 06:30
@erikd
Copy link
Contributor Author

erikd commented May 4, 2017

I've updated the PR so that the behavior at the API level of Error_EOF is the same as before. With this patch, Error_EOF is no longer returned as an exception, but as the Left of an either. Now in recvData we check the TLSError and if it is Error_EOF we return ByteString.empty.

@kazu-yamamoto
Copy link
Collaborator

This is just my opinion but I don't like IO (Either a).
IO itself means that this computation may fail.
I seems to me that IO (Either a) is redundant.
So, I would like to keep:

readExact :: Context -> Int -> IO Bytes

And I would like to have:

recvRecord :: Bool -> Context -> IO (Record Plaintext)

If advantages of IO (Either a) in this case were explained, I would change my mind.

@erikd
Copy link
Contributor Author

erikd commented May 8, 2017

IO itself means that this computation may fail.

I agree. The problem is that the existing code uses exceptions for flow control. In most languages this is considered a code smell. Exceptions are usually reserved for exceptional circumstances. One of the things that the commit is "fixing" is throwCore Error_EOF. I don't think that anyone could possibly argue that Error_EOF is an "exceptional" circumstance for a network connection.

I consider this the first patch in a series of patches that would remove all throwing of exceptions within TLS, catch all exceptions at the interface between TLS and lower levels and convert them into errors that a represented in the types. TLS would then provide at API of total functions to clients of TLS.

I know Haskell is not a total programming language, but it is possible to program in it as if it is.

The function recvRecord is currently:

recvRecord :: Bool    -- ^ flag to enable SSLv2 compat ClientHello reception
           -> Context -- ^ TLS context
           -> IO (Either TLSError (Record Plaintext))

I agree, the function signature does not express the partiality that result from exceptions, but removing the Either only makes it more partial. I think this function signature should remain as it is, but should add a contract in the comments:

-- This function catches all exceptions and converts them to TLSError. If exceptions escape
-- this function it should be considered a bug that needs to be fixed.
recvRecord :: Bool -> Context -> IO (Either TLSError (Record Plaintext))

@ocheron
Copy link
Contributor

ocheron commented May 8, 2017

I didn't realize disengageRecord uses throwError and not throwCore.
So going through terminate for all Error_Packet should be OK.

I still think the setEOF call in readExact should be kept there.

@erikd
Copy link
Contributor Author

erikd commented May 8, 2017

I still think the setEOF call in readExact should be kept there.

@ocheron Sorry, I don't understand that comment. I don't see how this PR changes the circumstances in which setEOF is called. In the old code setEOF is not called when Error_EOF is caught. That will still be true after this patch is applied. Do you meant that setEOF should be called on Error_EOF?

@kazu-yamamoto
Copy link
Collaborator

I agree with IO Either.

@kazu-yamamoto
Copy link
Collaborator

@erikd The current readExact does not call setEOF at all!

@erikd
Copy link
Contributor Author

erikd commented May 9, 2017

@erikd The current readExact does not call setEOF at all!

Yes, I am somewhat confused by @ocheron' s comment which is why I was asking for clarification.

@kazu-yamamoto
Copy link
Collaborator

One more item to discuss. Can Record typ ver (Fragment "") express EOF? If so, we can implement:

recvRecord :: Bool -> Context -> IO (Record Plaintext)

@erikd
Copy link
Contributor Author

erikd commented May 9, 2017

@kazu-yamamoto EOF is not the only failure state that is be communicated via the Either (eg there is also Error_Protocol) so its not possible to remove the Either.

@kazu-yamamoto
Copy link
Collaborator

@erikd Yes. But other true errors can be thrown.
I quickly hacked to remove Either in my local branch. I needed to modify many code but they got much simpler.

@ocheron
Copy link
Contributor

ocheron commented May 9, 2017

@kazu-yamamoto
Copy link
Collaborator

I finally recognized that Record typ ver (Fragment "") means a record with a header and an empty body, not EOF. So, this approach is not acceptable.

Now I fully support @erikd's approach.

@erikd
Copy link
Contributor Author

erikd commented May 9, 2017

@ocheron You are correct. I will update the PR.

Previously these were thrown as exceptions even though the error
types were correct to return then as a Left.

Closes: haskell-tls#220
@erikd erikd force-pushed the topic/error-packet-left branch from f6e88db to 03d7234 Compare May 9, 2017 12:51
@kazu-yamamoto
Copy link
Collaborator

LGTM.

@kazu-yamamoto kazu-yamamoto self-requested a review May 12, 2017 00:57
Copy link
Collaborator

@kazu-yamamoto kazu-yamamoto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

kazu-yamamoto added a commit to kazu-yamamoto/hs-tls that referenced this pull request May 12, 2017
@kazu-yamamoto
Copy link
Collaborator

Merged. Thank you for your contribution!

@erikd
Copy link
Contributor Author

erikd commented May 14, 2017

This has been merged. Closing.

@erikd erikd closed this May 14, 2017
@erikd erikd deleted the topic/error-packet-left branch May 14, 2017 22:25
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

Successfully merging this pull request may close these issues.

3 participants