Chromium Code Reviews| Index: net/quic/chromium/quic_chromium_client_session.cc |
| diff --git a/net/quic/chromium/quic_chromium_client_session.cc b/net/quic/chromium/quic_chromium_client_session.cc |
| index bdf9326be9dcb0f41aa93f682a509a59e8ee0add..7247c7a85967d1da6e6e68db6229e5ed3e9eee42 100644 |
| --- a/net/quic/chromium/quic_chromium_client_session.cc |
| +++ b/net/quic/chromium/quic_chromium_client_session.cc |
| @@ -187,8 +187,13 @@ class QuicServerPushHelper : public ServerPushDelegate::ServerPushHelper { |
| } // namespace |
| QuicChromiumClientSession::StreamRequest::StreamRequest( |
| - const base::WeakPtr<QuicChromiumClientSession>& session) |
| - : session_(session), stream_(nullptr) {} |
| + const base::WeakPtr<QuicChromiumClientSession>& session, |
|
xunjieli
2017/05/01 20:15:06
Does |session| always outlive the StreamRequest? W
Ryan Hamilton
2017/05/01 21:42:33
The StreamRequest may well outlive the session. Th
xunjieli
2017/05/02 17:23:05
Got it. That makes sense. The "Handle" approach is
|
| + bool requires_confirmation) |
| + : session_(session), |
| + requires_confirmation_(requires_confirmation), |
| + stream_(nullptr), |
| + next_state_(STATE_NONE), |
| + weak_factory_(this) {} |
| QuicChromiumClientSession::StreamRequest::~StreamRequest() { |
| if (stream_) |
| @@ -201,12 +206,11 @@ QuicChromiumClientSession::StreamRequest::~StreamRequest() { |
| int QuicChromiumClientSession::StreamRequest::StartRequest( |
| const CompletionCallback& callback) { |
| DCHECK(session_); |
| - int rv = session_->TryCreateStream(this); |
| - if (rv == ERR_IO_PENDING) { |
| + |
| + next_state_ = STATE_WAIT_FOR_CONFIRMATION; |
| + int rv = DoLoop(OK); |
| + if (rv == ERR_IO_PENDING) |
| callback_ = callback; |
| - } else { |
| - session_.reset(); |
| - } |
| return rv; |
| } |
| @@ -221,17 +225,98 @@ QuicChromiumClientSession::StreamRequest::ReleaseStream() { |
| void QuicChromiumClientSession::StreamRequest::OnRequestCompleteSuccess( |
| QuicChromiumClientStream* stream) { |
| + DCHECK_EQ(STATE_REQUEST_STREAM_COMPLETE, next_state_); |
| session_.reset(); |
| stream_ = stream; |
| - base::ResetAndReturn(&callback_).Run(OK); |
| + if (callback_) |
|
xunjieli
2017/05/01 20:15:05
I think callback_ is always valid, right? It's nev
Ryan Hamilton
2017/05/01 21:42:35
Ah. Good question. No, it's not guaranteed to be v
xunjieli
2017/05/02 17:23:05
Ah, that's subtle. Thanks for the comment.
|
| + DoCallback(OK); |
| } |
| void QuicChromiumClientSession::StreamRequest::OnRequestCompleteFailure( |
| int rv) { |
| + DCHECK_EQ(STATE_REQUEST_STREAM_COMPLETE, next_state_); |
| session_.reset(); |
| + if (callback_) |
| + DoCallback(rv); |
| +} |
| + |
| +void QuicChromiumClientSession::StreamRequest::OnIOComplete(int rv) { |
| + rv = DoLoop(rv); |
| + |
| + if (rv != ERR_IO_PENDING && !callback_.is_null()) { |
| + DoCallback(rv); |
| + } |
| +} |
| + |
| +void QuicChromiumClientSession::StreamRequest::DoCallback(int rv) { |
| + CHECK_NE(rv, ERR_IO_PENDING); |
| + CHECK(!callback_.is_null()); |
| + |
| + // The client callback can do anything, including destroying this class, |
| + // so any pending callback must be issued after everything else is done. |
| base::ResetAndReturn(&callback_).Run(rv); |
| } |
| +int QuicChromiumClientSession::StreamRequest::DoLoop(int rv) { |
| + do { |
| + State state = next_state_; |
| + next_state_ = STATE_NONE; |
| + switch (state) { |
| + case STATE_WAIT_FOR_CONFIRMATION: |
| + CHECK_EQ(OK, rv); |
| + rv = DoWaitForConfirmation(); |
| + break; |
| + case STATE_WAIT_FOR_CONFIRMATION_COMPLETE: |
| + rv = DoWaitForConfirmationComplete(rv); |
| + break; |
| + case STATE_REQUEST_STREAM: |
| + CHECK_EQ(OK, rv); |
| + rv = DoRequestStream(); |
| + break; |
| + case STATE_REQUEST_STREAM_COMPLETE: |
| + rv = DoRequestStreamComplete(rv); |
| + break; |
| + default: |
| + NOTREACHED() << "next_state_: " << next_state_; |
| + break; |
| + } |
| + } while (next_state_ != STATE_NONE && next_state_ && rv != ERR_IO_PENDING); |
| + |
| + return rv; |
| +} |
| + |
| +int QuicChromiumClientSession::StreamRequest::DoWaitForConfirmation() { |
| + next_state_ = STATE_WAIT_FOR_CONFIRMATION_COMPLETE; |
| + if (requires_confirmation_) |
|
xunjieli
2017/05/01 20:15:05
nit: add curly braces or use early return.
Ryan Hamilton
2017/05/01 21:42:35
Done.
|
| + return session_->WaitForHandshakeConfirmation( |
| + base::Bind(&QuicChromiumClientSession::StreamRequest::OnIOComplete, |
| + weak_factory_.GetWeakPtr())); |
| + |
| + return OK; |
| +} |
| + |
| +int QuicChromiumClientSession::StreamRequest::DoWaitForConfirmationComplete( |
| + int rv) { |
|
xunjieli
2017/05/01 20:15:05
nit: maybe add a DCHECK_NE(ERR_IO_PENDING, rv) her
Ryan Hamilton
2017/05/01 21:42:35
Done.
|
| + if (rv < 0) |
| + return rv; |
| + |
| + next_state_ = STATE_REQUEST_STREAM; |
| + return OK; |
| +} |
| + |
| +int QuicChromiumClientSession::StreamRequest::DoRequestStream() { |
| + next_state_ = STATE_REQUEST_STREAM_COMPLETE; |
| + |
| + return session_->TryCreateStream(this); |
| +} |
| + |
| +int QuicChromiumClientSession::StreamRequest::DoRequestStreamComplete(int rv) { |
| + DCHECK(rv == OK || !stream_); |
| + session_.reset(); |
| + |
| + return rv; |
| +} |
| + |
| QuicChromiumClientSession::QuicChromiumClientSession( |
| QuicConnection* connection, |
| std::unique_ptr<DatagramClientSocket> socket, |
| @@ -455,11 +540,23 @@ void QuicChromiumClientSession::RemoveObserver(Observer* observer) { |
| } |
| std::unique_ptr<QuicChromiumClientSession::StreamRequest> |
| -QuicChromiumClientSession::CreateStreamRequest() { |
| +QuicChromiumClientSession::CreateStreamRequest(bool requires_confirmation) { |
| // base::MakeUnique does not work because the StreamRequest constructor |
| // is private. |
| return std::unique_ptr<StreamRequest>( |
| - new StreamRequest(weak_factory_.GetWeakPtr())); |
| + new StreamRequest(weak_factory_.GetWeakPtr(), requires_confirmation)); |
| +} |
| + |
| +int QuicChromiumClientSession::WaitForHandshakeConfirmation( |
| + const CompletionCallback& callback) { |
| + if (!connection()->connected()) |
| + return ERR_CONNECTION_CLOSED; |
| + |
| + if (IsCryptoHandshakeConfirmed()) |
| + return OK; |
| + |
| + waiting_for_confirmation_callbacks_.push_back(callback); |
| + return ERR_IO_PENDING; |
| } |
| int QuicChromiumClientSession::TryCreateStream(StreamRequest* request) { |
| @@ -864,6 +961,8 @@ void QuicChromiumClientSession::OnCryptoHandshakeEvent( |
| ++it; |
| observer->OnCryptoHandshakeConfirmed(); |
| } |
| + |
| + NotifyAllWaitingForConfirmation(OK); |
|
xunjieli
2017/05/01 20:15:05
I like the new notification API!
Ryan Hamilton
2017/05/01 21:42:34
\o/ Thanks!
|
| } |
| QuicSpdySession::OnCryptoHandshakeEvent(event); |
| } |
| @@ -1006,6 +1105,7 @@ void QuicChromiumClientSession::OnConnectionClosed( |
| CloseAllStreams(ERR_UNEXPECTED); |
| CloseAllObservers(ERR_UNEXPECTED); |
| CancelAllRequests(ERR_CONNECTION_CLOSED); |
| + NotifyAllWaitingForConfirmation(ERR_CONNECTION_CLOSED); |
| NotifyFactoryOfSessionClosedLater(); |
| } |
| @@ -1274,6 +1374,14 @@ void QuicChromiumClientSession::CancelAllRequests(int net_error) { |
| } |
| } |
| +void QuicChromiumClientSession::NotifyAllWaitingForConfirmation(int net_error) { |
| + // Post tasks to avoid reentrancy. |
| + for (auto callback : waiting_for_confirmation_callbacks_) |
|
xunjieli
2017/05/01 20:15:06
nit: need a pair of {} here for the for-loop.
Ryan Hamilton
2017/05/01 21:42:32
Hm. I thought this was not needed because the body
xunjieli
2017/05/02 17:23:05
Got it. I didn't know that braces are optional for
|
| + task_runner_->PostTask(FROM_HERE, base::Bind(callback, net_error)); |
| + |
| + waiting_for_confirmation_callbacks_.clear(); |
| +} |
| + |
| std::unique_ptr<base::Value> QuicChromiumClientSession::GetInfoAsValue( |
| const std::set<HostPortPair>& aliases) { |
| std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |