Capture packets using man-in-the-middle (MITM) proxy

Sure! Considering only the success path for a moment, the state machine graph looks like this:

We enter beganConnecting when we read the first .head message. The upgrade is complete when two things happen: we have to have received the .end associated with that first message, and the TCP connection has to succeed.

That leads to this diamond pattern in the state machine. If we channelRead .end before the connect succeeds, we enter awaitingConnection. If the connect succeeds before we read .end, we enter awaitingEnd. In each case, we are waiting for the other event to happen.

Thus, to your detailed question:

When we're in awaitingConnection we've read the .end of the HTTP message that triggered our upgrade. Because this is a CONNECT request, any subsequent bytes are presumably part of the TCP stream the client wants to send to the other server. We don't know what format those are, so we can't read them! Hence "this must not be HTTP anymore". But we can't leave the channel pipeline yet, because we're still waiting for the TCP connection to succeed.

In connectSucceed, we move to upgrade complete because the thing we were waiting for has happened!

It sure does, you shouldn't do that.

CONNECT requests that the proxy set up a TCP connection to another peer. What happens next is not well defined: the client might try to do HTTP, or it might try to do TLS, or SMTP, or any number of other things. You can't safely add HTTP handlers there because you don't know what that next protocol would be.