-
-
Notifications
You must be signed in to change notification settings - Fork 343
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
SSL support and a Stream API #107
Conversation
cc @dabeaz: I suspect you won't find this useful at all, but hey :-) |
Codecov Report
@@ Coverage Diff @@
## master #107 +/- ##
==========================================
+ Coverage 98.44% 99.01% +0.56%
==========================================
Files 53 59 +6
Lines 6116 7996 +1880
Branches 476 568 +92
==========================================
+ Hits 6021 7917 +1896
+ Misses 80 62 -18
- Partials 15 17 +2
Continue to review full report at Codecov.
|
Still should probably rename wait_writable
Should (hopefully) fix travis builds
Forgetting to call do_handshake gives you a SSL connection that works perfectly except that it has no MITM protection: https://bugs.python.org/issue30141
a java echo server! a pyopenssl equivalent that somehow seems to be working now? the body of _retry is duplicated 3 times so I can get more detailed debugging and coverage information depending on who called it!
Maybe a bit fragile though... checkpointing before attempting a new idea
And use it in MockClock to get better behavior when using wait_all_tasks_blocked and autojump_threshold=0 together. Potentially useful in general as well.
This is starting to look like something real! And ssl.py is approaching a 2:1 ratio of comments to code, which is probably about right.
(it's an AbstractAsyncContextManager, but that doesn't exist, even in py36)
Two potential minor additions that occurred to me:
|
Another thing to think about in the future, but probably not right now: automagically optimizing TLS record size. (SSLObject doesn't expose this directly, but basically it has to create a separate record each time you call |
Staring at the urllib3 code is making me wonder if we should jump through the necessary hoops so that when Rationale: they want the following semantics: initially, we start concurrently sending a request and receiving for response headers. Normally, we send the whole request, and then the response headers arrive. But sometimes, when we're only partly through sending the request, the response headers arrive preemptively. Either way, as soon as response headers arrive, we need to stop sending and return (!) the response headers. Then, our caller will make separate calls (!!) to ask us to read chunks of the response body (like an iterator). So the problem here is that we need to start up a task to send the request, and then after we get the response headers we need to either stop this task or else let it keep running in the background. Either is OK and would be correct, but the only reliable way we have to stop it is to cancel it (we can't assume it will notice any more gentle method, like setting a flag, because it might be blocked on I/O). And letting it continue after we return from the method is quite awkward, because it means that someone higher up the stack has to take responsibility for it. I'm not sure we should rule out the "run in background" solution, because I know Cory wants to add HTTP/2 support to requests as well, and that will mean finding some way to have a task running in the background for as long as each connection is alive, because someone has to respond promptly to pings, and solving that might provide a solution here as well. But for this comment let's consider the version where we make cancellation work. To do this: first, if The trickiest thing is how to report the resulting state. Technically at this point the
I'm leaning towards the latter. When someone cancels a send, they're saying they don't really want to send it, and in fact it's urgent that they stop sending it immediately, to the point that it's worth risking losing sync over. In general I don't think it's a requirement that Though, hmm, note that for TLS-over-TLS to survive cancellation, we actually do need the inner stream to fully survive. So that's a pretty good argument for the former. (Though this doesn't need an explicit flush command; it's enough that everything will be flushed the next time it does a non-trivial |
|
I think I'll merge this tomorrow, when I'm more awake. Todo:
|
@@ -29,6 +29,18 @@ if [ "$USE_PYPY_NIGHTLY" = "1" ]; then | |||
source testenv/bin/activate | |||
fi | |||
|
|||
if [ "$USE_PYPY_RELEASE" = "1" ]; then | |||
curl -Lo pypy.tar.bz2 https://bitbucket.org/squeaky/portable-pypy/downloads/pypy3.5-5.7.1-beta-linux_x86_64-portable.tar.bz2 |
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 believe this is not beta anymore.
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's the URL where he posted it; what do you want me to do here :-). Note that "beta" here doesn't mean "this is a beta of 5.7.1", it means "this is 5.7.1, and watch out b/c the py3 support is still considered beta quality".
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.
Ah, my bad. Ignore comment then.
ssl_context.check_hostname = False | ||
s = SSLStream(StapledStream(process.stdin, process.stdout), ssl_context) | ||
|
||
[Note: subprocess support is not implemented yet, but that's the |
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.
.. note ::
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 think I'll leave this as is for now, it's not really a call-out-box kind of note, more like a whispered parenthetical.
If that makes any sense at all, which it probably doesn't.
self._held = False | ||
|
||
|
||
class UnLock: |
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 naming of UnLock (if I understand correctly) seem weird, and counterintuitive. I'm going to guess many people will read it as Unlocking something. Maybe naming as "Restricive" of "Exclusionary" ? Or RaisingLock ?
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, this is definitely a bit over-cutesy. (Note that it isn't a public API, though.) Also it should probably be refactored a bit since currently it's written as a generic object that can raise any exception, but in fact every single caller uses it to raise ResourceBusy
.
@@ -705,3 +741,5 @@ def _make_simple_sock_method_wrapper(methname, wait_fn, maybe_avail=False): | |||
# else: | |||
# raise OSError("getaddrinfo returned an empty list") | |||
# __all__.append("create_connection") | |||
|
|||
|
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.
Read until here so far. I'm not going to assume I can wrap all that in my head, but I did not saw anything particularly wrong. For now I'm going to switch task a bit.
:class:`~trio.ssl.SSLStream`:: | ||
|
||
# Get a raw SocketStream connection to the proxy: | ||
s0 = await open_tcp_stream("proxy", 443) |
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 doesn't look like open_tcp_stream
exists.
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, that's correct, but #145 will eventually add it I think :-).
In general this PR has gotten kind of out of hand, so I want to try and get it merged and turn most of these comments into follow-up issues. And the docs in particular are in a bit of a mess because there isn't really a good way to document a library that has half of a high-level networking API implemented... best thing is to finish it and then figure out how to make the docs good :-). This is a useful reminder to add some sort of "please excuse our dust" note to the docs in the interim though...
They're either todone or filed as separate issues now.
Okay, let's do this! Wooo! |
👍 |
Is outgoing MemoryBIO flushed out when unwrap is called? |
The outgoing MemoryBIO is flushed after every operation. unwrap() also does
a full, clean shutdown of the TLS layer by sending a close-notify message,
and waiting for the other side to send a close-notify of its own.
…On Sat, Mar 31, 2018, 04:27 Imran Geriskovan ***@***.***> wrote:
Is outgoing MemoryBIO flushed out when unwrap is called?
—
You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub
<#107 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAlOaJ9krbt7HSg8QUP2etZ44c73CBtlks5tj2g3gaJpZM4MiF0q>
.
|
This is currently a first attempt with no tests, I'm not sure I understand
SSLObject
's semantics, and even if I got that right then the implementation is still a bit tricky for my taste (and I'm not 100% sure it's correct). But AFAICT it does work!My current understanding of
SSLObject
is:do_handshake
,read
,write
, andunwrap
SSLWantWriteError
SSLWantReadError
.SSLWantReadError
then we need to send on any outgoing data, refill the incoming buffer, and then retry the operation.In particular, we assume that we can synchronously send any outgoing data before refilling the incoming buffer. I think (hope?) this is safe according to the SSL state machine and won't cause deadlocks, but am not 100% sure.
If this is wrong then the code is definitely broken. If it's correct then the code might be correct :-).
Well, and
unwrap
is definitely broken right now, because it doesn't seem to follow the "keep trying until you succeed" model. Need to investigate further.Implementing some kind of
suppress_ragged_eofs
functionality would probably be good, given how pervasive this is.This currently allows multiple tasks to be in
recv
orsendall
at the same time (as a side-effect of allowingrecv
andsendall
to coordinate with each other) – this probably encourages bad habits. I guess a simple boolean "lock" on each method would be enough to stop it.