Chromium Code Reviews| Index: components/cronet/ios/cronet_bidirectional_stream.cc |
| diff --git a/components/cronet/ios/cronet_bidirectional_stream.cc b/components/cronet/ios/cronet_bidirectional_stream.cc |
| index d3c881b472e185f481329563b53caed36a1dfe95..f987b26e5ca23bb82d489ca28323f4d8a26271a2 100644 |
| --- a/components/cronet/ios/cronet_bidirectional_stream.cc |
| +++ b/components/cronet/ios/cronet_bidirectional_stream.cc |
| @@ -32,12 +32,19 @@ |
| namespace cronet { |
| +CronetBidirectionalStream::PendingWriteData::PendingWriteData() {} |
| + |
| +CronetBidirectionalStream::PendingWriteData::~PendingWriteData() {} |
| + |
| CronetBidirectionalStream::CronetBidirectionalStream( |
| CronetEnvironment* environment, |
| Delegate* delegate) |
| : read_state_(NOT_STARTED), |
| write_state_(NOT_STARTED), |
| write_end_of_stream_(false), |
| + request_headers_sent_(false), |
| + disable_auto_flush_(false), |
| + delay_headers_until_flush_(false), |
| environment_(environment), |
| delegate_(delegate) {} |
| @@ -98,6 +105,13 @@ bool CronetBidirectionalStream::WriteData(const char* buffer, |
| return true; |
| } |
| +bool CronetBidirectionalStream::Flush() { |
| + environment_->PostToNetworkThread( |
| + FROM_HERE, base::Bind(&CronetBidirectionalStream::FlushOnNetworkThread, |
| + base::Unretained(this))); |
| + return true; |
| +} |
| + |
| void CronetBidirectionalStream::Cancel() { |
| environment_->PostToNetworkThread( |
| FROM_HERE, base::Bind(&CronetBidirectionalStream::CancelOnNetworkThread, |
| @@ -116,9 +130,16 @@ void CronetBidirectionalStream::Destroy() { |
| void CronetBidirectionalStream::OnStreamReady(bool request_headers_sent) { |
| DCHECK(environment_->IsOnNetworkThread()); |
| DCHECK(write_state_ == STARTED); |
| - write_state_ = WAITING_FOR_WRITE; |
| - if (write_end_of_stream_) |
| + request_headers_sent_ = request_headers_sent; |
| + write_state_ = WAITING_FOR_FLUSH; |
| + if (write_end_of_stream_) { |
| + if (!request_headers_sent) { |
|
xunjieli
2016/06/10 16:30:49
Should we not check |write_end_stream_|? Currently
mef
2016/06/10 18:36:36
But that would never come if auto flush is enabled
xunjieli
2016/06/10 19:00:01
You are right. Hopefully we will get rid of auto f
|
| + // If there is no data to write, then just send headers explicitly. |
| + bidi_stream_->SendRequestHeaders(); |
| + request_headers_sent_ = true; |
| + } |
| write_state_ = WRITING_DONE; |
| + } |
| delegate_->OnStreamReady(); |
| } |
| @@ -162,10 +183,17 @@ void CronetBidirectionalStream::OnDataRead(int bytes_read) { |
| void CronetBidirectionalStream::OnDataSent() { |
| DCHECK(environment_->IsOnNetworkThread()); |
| DCHECK(write_state_ == WRITING); |
|
xunjieli
2016/06/10 16:30:49
DCHECK_EQ?
mef
2016/06/10 18:36:36
Done.
|
| - write_state_ = WAITING_FOR_WRITE; |
| - delegate_->OnDataSent(write_buffer_->data()); |
| - // Free the write buffer. |
| - write_buffer_ = nullptr; |
| + write_state_ = WAITING_FOR_FLUSH; |
| + for (scoped_refptr<net::IOBuffer> buffer : |
| + sending_write_data_->write_buffer_list) { |
| + delegate_->OnDataSent(buffer->data()); |
| + } |
| + sending_write_data_.reset(); |
| + // Send data flushed while other data was sending. |
| + if (flushing_write_data_) { |
| + SendFlushingWriteData(); |
|
xunjieli
2016/06/10 16:30:50
Maybe invoke FlushOnNetworkThread() directly? This
mef
2016/06/10 18:36:36
I think they are different.
FlushOnNetworkThread i
|
| + return; |
| + } |
| if (write_end_of_stream_) |
| write_state_ = WRITING_DONE; |
| MaybeOnSucceded(); |
| @@ -195,7 +223,7 @@ void CronetBidirectionalStream::StartOnNetworkThread( |
| std::move(request_info), environment_->GetURLRequestContext() |
| ->http_transaction_factory() |
| ->GetSession(), |
| - /*send_request_headers_automatically=*/true, this)); |
| + !delay_headers_until_flush_, this)); |
| DCHECK(read_state_ == NOT_STARTED && write_state_ == NOT_STARTED); |
| read_state_ = write_state_ = STARTED; |
| } |
| @@ -234,19 +262,68 @@ void CronetBidirectionalStream::WriteDataOnNetworkThread( |
| bool end_of_stream) { |
| DCHECK(environment_->IsOnNetworkThread()); |
| DCHECK(write_buffer); |
| - DCHECK(!write_buffer_); |
| - if (write_state_ != WAITING_FOR_WRITE) { |
| - DLOG(ERROR) << "Unexpected Write Data in write_state " << write_state_; |
| + if (!bidi_stream_) { |
| + DLOG(ERROR) << "Unexpected Flush Data in write_state " << write_state_; |
| // Invoke OnFailed unless it is already invoked. |
| if (write_state_ != ERROR) |
| OnFailed(net::ERR_UNEXPECTED); |
| return; |
| } |
| - write_state_ = WRITING; |
| + if (!pending_write_data_) |
| + pending_write_data_.reset(new PendingWriteData()); |
| + pending_write_data_->write_buffer_list.push_back(write_buffer); |
| + pending_write_data_->write_buffer_len_list.push_back(buffer_size); |
| write_end_of_stream_ = end_of_stream; |
| + if (!disable_auto_flush_) |
| + FlushOnNetworkThread(); |
| +} |
| + |
| +void CronetBidirectionalStream::FlushOnNetworkThread() { |
| + DCHECK(environment_->IsOnNetworkThread()); |
| + if (!bidi_stream_) |
| + return; |
| + // If there is no data to flush, may need to send headers. |
| + if (!pending_write_data_) { |
|
xunjieli
2016/06/10 16:30:50
Also need to check |flushing_write_data_| ?
mef
2016/06/10 18:36:36
Hrm, I think if |flushing_write_data_| is not null
|
| + if (!request_headers_sent_) { |
| + request_headers_sent_ = true; |
| + bidi_stream_->SendRequestHeaders(); |
| + } |
| + return; |
| + } |
| + // If request headers are not sent yet, they will be sent with the data. |
| + request_headers_sent_ = true; |
| + // Move pending data to the flushing list. |
| + if (flushing_write_data_) { |
| + std::move(pending_write_data_->write_buffer_list.begin(), |
| + pending_write_data_->write_buffer_list.end(), |
| + std::back_inserter(flushing_write_data_->write_buffer_list)); |
| + std::move(pending_write_data_->write_buffer_len_list.begin(), |
| + pending_write_data_->write_buffer_len_list.end(), |
| + std::back_inserter(flushing_write_data_->write_buffer_len_list)); |
| + } else { |
| + std::swap(flushing_write_data_, pending_write_data_); |
| + } |
| + if (!sending_write_data_) |
|
xunjieli
2016/06/10 19:00:01
Can this check be just "if (write_state_ != WRITIN
mef
2016/06/10 19:11:28
Done.
|
| + SendFlushingWriteData(); |
| +} |
| - write_buffer_ = write_buffer; |
| - bidi_stream_->SendData(write_buffer_.get(), buffer_size, end_of_stream); |
| +void CronetBidirectionalStream::SendFlushingWriteData() { |
| + DCHECK(environment_->IsOnNetworkThread()); |
| + DCHECK(!sending_write_data_); |
| + if (write_state_ != WAITING_FOR_FLUSH) { |
|
xunjieli
2016/06/10 16:30:50
Flush() can be called anytime after OnStreamReady(
mef
2016/06/10 18:36:36
SendFlushingWriteData is similar to nativeWritevDa
xunjieli
2016/06/10 19:00:01
I learned from Andrei that we should re-use routin
xunjieli
2016/06/10 19:04:38
In other words, iI am wondering if we can get rid
mef
2016/06/10 19:11:28
I don't think we can though. FlushOnNetworkThread
mef
2016/06/10 20:03:48
Per offline discussion this is current behavior on
|
| + DLOG(ERROR) << "Unexpected Flush Data in write_state " << write_state_; |
| + // Invoke OnFailed unless it is already invoked. |
| + if (write_state_ != ERROR) |
| + OnFailed(net::ERR_UNEXPECTED); |
| + return; |
| + } |
| + if (!flushing_write_data_) |
| + return; |
| + write_state_ = WRITING; |
| + sending_write_data_.swap(flushing_write_data_); |
| + bidi_stream_->SendvData(sending_write_data_->write_buffer_list, |
| + sending_write_data_->write_buffer_len_list, |
| + write_end_of_stream_); |
| } |
| void CronetBidirectionalStream::CancelOnNetworkThread() { |