-
Notifications
You must be signed in to change notification settings - Fork 86
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
Further updates to rustls 0.20 #68
Conversation
90732ba
to
6945939
Compare
if prev == buf.remaining() && would_block { | ||
Poll::Ready(Err(err)) | ||
} else { | ||
break; |
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.
Should we make sure to yield UnexpectedEof
on future reads in this case?
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.
Yeah, I think so?
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 we get UnexpectedEof
from the reader().read()
call, that means the reader currently has:
- No received plaintext left to read, and
!peer_cleanly_closed
, which expands to!(has_received_close_notify && !self.message_deframer.has_pending())
, andhas_seen_eof
on the input stream
has_seen_eof
should be permanent, but if we have not yet received a CloseNotify
it is possible that there are still frames pending in the deframer that contain a CloseNotify
. So we should actually not eagerly return UnexpectedEof
unless the reader gives it to us.
Do you agree?
In testing #69, we found that the diff --git a/tokio-rustls/src/common/mod.rs b/tokio-rustls/src/common/mod.rs
index 77d371d..05789b1 100644
--- a/tokio-rustls/src/common/mod.rs
+++ b/tokio-rustls/src/common/mod.rs
@@ -229,63 +229,61 @@ impl<'a, IO: AsyncRead + AsyncWrite + Unpin, S: Connection> AsyncRead for Stream
let prev = buf.remaining();
while buf.remaining() != 0 {
- let mut would_block = false;
+ let mut io_pending = false;
// read a packet
while !self.eof && self.session.wants_read() {
- match self.read_io(cx) {
+ match dbg!(self.read_io(cx)) {
Poll::Ready(Ok(0)) => {
self.eof = true;
break;
}
Poll::Ready(Ok(_)) => (),
Poll::Pending => {
- would_block = true;
+ io_pending = true;
break;
}
Poll::Ready(Err(err)) => return Poll::Ready(Err(err)),
}
}
- return match self.session.reader().read(buf.initialize_unfilled()) {
- Ok(0) if prev == buf.remaining() && would_block => Poll::Pending,
+ return match dbg!(self.session.reader().read(buf.initialize_unfilled())) {
+ // The TLS session has been closed cleanly, we can return since there will
+ // be no more data to read from the session.
+ Ok(0) => break,
+
+ // Read some bytes
Ok(n) => {
buf.advance(n);
-
- if self.eof || would_block {
+ if self.eof || io_pending {
break;
} else {
continue;
}
}
- // Rustls may return `WouldBlock` instead of `Ok(0)` if the
- // stream has reached EOF without receiving a `CloseNotify` from
- // the peer. Therefore, we must determine whether a `WouldBlock`
- // here means EOF, or if there is more data to read.
+ // Rustls returns `WouldBlock` if it needs more data before returning.
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
- if prev == buf.remaining() && would_block {
+ if prev == buf.remaining() && io_pending {
Poll::Pending
- } else if self.eof || would_block {
+ } else if self.eof || io_pending {
break;
} else {
continue;
}
}
+
+ // `UnexpectedEof` means the peer closed the connection without sending
+ // `CloseNotify`. Declare EOF and propagate the error.
Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => {
- self.eof = true;
- if prev == buf.remaining() && would_block {
+ if prev == buf.remaining() {
Poll::Ready(Err(err))
} else {
break;
}
}
- Err(ref err)
- if err.kind() == io::ErrorKind::ConnectionAborted
- && prev != buf.remaining() =>
- {
- break
- }
+
+ // This should be unreachable.
Err(err) => Poll::Ready(Err(err)),
};
}
diff --git a/tokio-rustls/src/common/test_stream.rs b/tokio-rustls/src/common/test_stream.rs
index 14766c0..a1730d1 100644
--- a/tokio-rustls/src/common/test_stream.rs
+++ b/tokio-rustls/src/common/test_stream.rs
@@ -217,8 +217,8 @@ async fn stream_eof() -> io::Result<()> {
let mut stream = Stream::new(&mut good, &mut client).set_eof(true);
let mut buf = Vec::new();
- stream.read_to_end(&mut buf).await?;
- assert_eq!(buf.len(), 0);
+ let result = stream.read_to_end(&mut buf).await;
+ assert_eq!(result.err().map(|e| e.kind()), Some(io::ErrorKind::UnexpectedEof));
Ok(()) as io::Result<()>
} This still fails |
1bbc747
to
698b728
Compare
@hawkw would you have a chance to look at this? Would be nice to figure out if we have the reader semantics right. |
Checking it out right now, sorry it took me a few days to get to this! |
@hawkw gentle ping? 🙂 |
This looks great to me, are you ready to merge? |
I think this is ready to be merged into the target branch, yes. Probably also fine to have on master. |
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.
sorry it took me so long to look at this, seems good overall!
if prev == buf.remaining() && would_block { | ||
Poll::Ready(Err(err)) | ||
} else { | ||
break; |
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.
Yeah, I think so?
Reverted the assert changes and updated to current rustls main. On further investigation, I convinced myself the change relating to |
Updated to final rustls 0.20 release. |
If there are no more comments, I plan to merge this PR in next two days. |
It's be cool to expose the |
@paolobarbolini good suggestion. Added a commit that forwards the |
* update to rustls 0.20 Signed-off-by: Eliza Weisman <eliza@buoyant.io> * track simple renamings in rustls Signed-off-by: Eliza Weisman <eliza@buoyant.io> * use reader/writer methods Signed-off-by: Eliza Weisman <eliza@buoyant.io> * fix find and replace Signed-off-by: Eliza Weisman <eliza@buoyant.io> * use rustls-pemfile crate for pem file parsing Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update misc api breakage Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update client example with api changes Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update server example with new APIs Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update test_stream test Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update tests to use new APIs Signed-off-by: Eliza Weisman <eliza@buoyant.io> * rm unused imports Signed-off-by: Eliza Weisman <eliza@buoyant.io> * handle rustls `WouldBlock` on eof Signed-off-by: Eliza Weisman <eliza@buoyant.io> * expect rustls to return wouldblock in tests Signed-off-by: Eliza Weisman <eliza@buoyant.io> * i think this is *actually* the right EOF behavior Signed-off-by: Eliza Weisman <eliza@buoyant.io> * bump version Signed-off-by: Eliza Weisman <eliza@buoyant.io> * okay that seems to fix it Signed-off-by: Eliza Weisman <eliza@buoyant.io> * update to track builder API changes Signed-off-by: Eliza Weisman <eliza@buoyant.io> * actually shutdown read side on close notify Signed-off-by: Eliza Weisman <eliza@buoyant.io> * Further updates to rustls 0.20 (#68) * Adapt to RootCertStore API changes * Handle UnexpectedEof errors * Rename would_block to io_pending * Try to make badssl test failures more verbose * Rebuild AsyncRead impl * Upgrade to current rustls * Revert to using assert!() * Update to rustls 0.20 * Forward rustls features Co-authored-by: Dirkjan Ochtman <dirkjan@ochtman.nl>
Note: this targets the branch for #64.