Chromium Code Reviews| Index: net/http/http_pipelined_connection_impl.cc |
| diff --git a/net/http/http_pipelined_connection_impl.cc b/net/http/http_pipelined_connection_impl.cc |
| index aa3d1788d50432829b8843587eefe52805d42ef7..6750f8c2a09657073c68fff7adcaa23d32d7d960 100644 |
| --- a/net/http/http_pipelined_connection_impl.cc |
| +++ b/net/http/http_pipelined_connection_impl.cc |
| @@ -34,25 +34,26 @@ HttpPipelinedConnectionImpl::HttpPipelinedConnectionImpl( |
| completed_one_request_(false), |
| ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), |
| send_next_state_(SEND_STATE_NONE), |
| + send_still_on_call_stack_(false), |
| ALLOW_THIS_IN_INITIALIZER_LIST(send_io_callback_( |
| this, &HttpPipelinedConnectionImpl::OnSendIOCallback)), |
| - send_user_callback_(NULL), |
| read_next_state_(READ_STATE_NONE), |
| + active_read_id_(0), |
| + read_still_on_call_stack_(false), |
| ALLOW_THIS_IN_INITIALIZER_LIST(read_io_callback_( |
| - this, &HttpPipelinedConnectionImpl::OnReadIOCallback)), |
| - read_user_callback_(NULL) { |
| + this, &HttpPipelinedConnectionImpl::OnReadIOCallback)) { |
| CHECK(connection_.get()); |
| } |
| HttpPipelinedConnectionImpl::~HttpPipelinedConnectionImpl() { |
| CHECK_EQ(depth(), 0); |
| CHECK(stream_info_map_.empty()); |
| - CHECK(deferred_request_queue_.empty()); |
| + CHECK(pending_send_request_queue_.empty()); |
| CHECK(request_order_.empty()); |
| CHECK_EQ(send_next_state_, SEND_STATE_NONE); |
| CHECK_EQ(read_next_state_, READ_STATE_NONE); |
| - CHECK(!send_user_callback_); |
| - CHECK(!read_user_callback_); |
| + CHECK(!active_send_request_.get()); |
| + CHECK(!active_read_id_); |
| if (!usable_) { |
| connection_->socket()->Disconnect(); |
| } |
| @@ -105,7 +106,6 @@ void HttpPipelinedConnectionImpl::OnStreamDeleted(int pipeline_id) { |
| stream_info_map_[pipeline_id].parser.reset(); |
| } |
| CHECK(!stream_info_map_[pipeline_id].parser.get()); |
| - CHECK(!stream_info_map_[pipeline_id].read_headers_callback); |
| stream_info_map_.erase(pipeline_id); |
| delegate_->OnPipelineHasCapacity(this); |
| @@ -123,18 +123,18 @@ int HttpPipelinedConnectionImpl::SendRequest(int pipeline_id, |
| return ERR_PIPELINE_EVICTION; |
| } |
| - DeferredSendRequest deferred_request; |
| - deferred_request.pipeline_id = pipeline_id; |
| - deferred_request.request_line = request_line; |
| - deferred_request.headers = headers; |
| - deferred_request.request_body = request_body; |
| - deferred_request.response = response; |
| - deferred_request.callback = callback; |
| - deferred_request_queue_.push(deferred_request); |
| + PendingSendRequest* send_request = new PendingSendRequest; |
| + send_request->pipeline_id = pipeline_id; |
| + send_request->request_line = request_line; |
| + send_request->headers = headers; |
| + send_request->request_body = request_body; |
| + send_request->response = response; |
| + send_request->callback = callback; |
| + pending_send_request_queue_.push(send_request); |
| int rv; |
| if (send_next_state_ == SEND_STATE_NONE) { |
| - send_next_state_ = SEND_STATE_NEXT_REQUEST; |
| + send_next_state_ = SEND_STATE_START_IMMEDIATELY; |
| rv = DoSendRequestLoop(OK); |
|
mmenke
2011/11/11 16:46:35
It might be a little simpler just to only set send
James Simonsen
2011/11/11 19:26:08
It would definitely merge the two cases, which wou
mmenke
2011/11/14 16:25:12
I think that setting the callback after the call t
|
| } else { |
| rv = ERR_IO_PENDING; |
| @@ -149,13 +149,19 @@ int HttpPipelinedConnectionImpl::DoSendRequestLoop(int result) { |
| SendRequestState state = send_next_state_; |
| send_next_state_ = SEND_STATE_NONE; |
| switch (state) { |
| - case SEND_STATE_NEXT_REQUEST: |
| - rv = DoSendNextRequest(rv); |
| + case SEND_STATE_START_IMMEDIATELY: |
| + rv = DoStartRequestImmediately(rv); |
| + break; |
| + case SEND_STATE_START_NEXT_DEFERRED_REQUEST: |
| + rv = DoStartNextDeferredRequest(rv); |
| + break; |
| + case SEND_STATE_SEND_ACTIVE_REQUEST: |
| + rv = DoSendActiveRequest(rv); |
| break; |
| case SEND_STATE_COMPLETE: |
| rv = DoSendComplete(rv); |
| break; |
| - case SEND_STATE_UNUSABLE: |
| + case SEND_STATE_EVICT_PENDING_REQUESTS: |
| rv = DoEvictPendingSendRequests(rv); |
| break; |
| default: |
| @@ -164,91 +170,101 @@ int HttpPipelinedConnectionImpl::DoSendRequestLoop(int result) { |
| break; |
| } |
| } while (rv != ERR_IO_PENDING && send_next_state_ != SEND_STATE_NONE); |
| + send_still_on_call_stack_ = false; |
| return rv; |
| } |
| void HttpPipelinedConnectionImpl::OnSendIOCallback(int result) { |
| - CHECK(send_user_callback_); |
| + CHECK(active_send_request_.get()); |
| DoSendRequestLoop(result); |
| } |
| -int HttpPipelinedConnectionImpl::DoSendNextRequest(int result) { |
| - CHECK(!deferred_request_queue_.empty()); |
| - const DeferredSendRequest& deferred_request = deferred_request_queue_.front(); |
| - CHECK(ContainsKey(stream_info_map_, deferred_request.pipeline_id)); |
| - if (stream_info_map_[deferred_request.pipeline_id].state == STREAM_CLOSED) { |
| - deferred_request_queue_.pop(); |
| - if (deferred_request_queue_.empty()) { |
| - send_next_state_ = SEND_STATE_NONE; |
| - } else { |
| - send_next_state_ = SEND_STATE_NEXT_REQUEST; |
| +int HttpPipelinedConnectionImpl::DoStartRequestImmediately(int result) { |
| + CHECK(!active_send_request_.get()); |
| + CHECK_EQ(static_cast<size_t>(1), pending_send_request_queue_.size()); |
| + send_still_on_call_stack_ = true; |
| + active_send_request_.reset(pending_send_request_queue_.front()); |
| + pending_send_request_queue_.pop(); |
| + send_next_state_ = SEND_STATE_SEND_ACTIVE_REQUEST; |
| + return OK; |
| +} |
| + |
| +int HttpPipelinedConnectionImpl::DoStartNextDeferredRequest(int result) { |
| + CHECK(!send_still_on_call_stack_); |
| + CHECK(!active_send_request_.get()); |
| + |
| + while (!pending_send_request_queue_.empty()) { |
| + scoped_ptr<PendingSendRequest> next_request( |
| + pending_send_request_queue_.front()); |
| + pending_send_request_queue_.pop(); |
| + CHECK(ContainsKey(stream_info_map_, next_request->pipeline_id)); |
| + if (stream_info_map_[next_request->pipeline_id].state != STREAM_CLOSED) { |
| + active_send_request_.reset(next_request.release()); |
| + send_next_state_ = SEND_STATE_SEND_ACTIVE_REQUEST; |
| + return OK; |
| } |
| - return OK; |
| - } |
| - CHECK(stream_info_map_[deferred_request.pipeline_id].parser.get()); |
| - int rv = stream_info_map_[deferred_request.pipeline_id].parser->SendRequest( |
| - deferred_request.request_line, |
| - deferred_request.headers, |
| - deferred_request.request_body, |
| - deferred_request.response, |
| - &send_io_callback_); |
| - // |result| == ERR_IO_PENDING means this function was *not* called on the same |
| - // stack as SendRequest(). That means we returned ERR_IO_PENDING to |
| - // SendRequest() earlier and will need to invoke its callback. |
| - if (result == ERR_IO_PENDING || rv == ERR_IO_PENDING) { |
| - send_user_callback_ = deferred_request.callback; |
| } |
| - stream_info_map_[deferred_request.pipeline_id].state = STREAM_SENDING; |
| + |
| + send_next_state_ = SEND_STATE_NONE; |
| + return OK; |
| +} |
| + |
| +int HttpPipelinedConnectionImpl::DoSendActiveRequest(int result) { |
| + CHECK(stream_info_map_[active_send_request_->pipeline_id].parser.get()); |
| + int rv = stream_info_map_[active_send_request_->pipeline_id].parser-> |
| + SendRequest(active_send_request_->request_line, |
| + active_send_request_->headers, |
| + active_send_request_->request_body, |
| + active_send_request_->response, |
| + &send_io_callback_); |
| + stream_info_map_[active_send_request_->pipeline_id].state = STREAM_SENDING; |
| send_next_state_ = SEND_STATE_COMPLETE; |
| return rv; |
| } |
| int HttpPipelinedConnectionImpl::DoSendComplete(int result) { |
| - CHECK(!deferred_request_queue_.empty()); |
| - const DeferredSendRequest& deferred_request = deferred_request_queue_.front(); |
| - CHECK_EQ(stream_info_map_[deferred_request.pipeline_id].state, |
| - STREAM_SENDING); |
| - request_order_.push(deferred_request.pipeline_id); |
| - stream_info_map_[deferred_request.pipeline_id].state = STREAM_SENT; |
| - deferred_request_queue_.pop(); |
| + CHECK(active_send_request_.get()); |
| + CHECK_EQ(STREAM_SENDING, |
| + stream_info_map_[active_send_request_->pipeline_id].state); |
| + |
| + request_order_.push(active_send_request_->pipeline_id); |
| + stream_info_map_[active_send_request_->pipeline_id].state = STREAM_SENT; |
| + |
| if (result == ERR_SOCKET_NOT_CONNECTED && completed_one_request_) { |
| result = ERR_PIPELINE_EVICTION; |
| } |
| if (result < OK) { |
| - send_next_state_ = SEND_STATE_UNUSABLE; |
| usable_ = false; |
| } |
| - if (send_user_callback_) { |
| - MessageLoop::current()->PostTask( |
| - FROM_HERE, |
| - method_factory_.NewRunnableMethod( |
| - &HttpPipelinedConnectionImpl::FireUserCallback, |
| - deferred_request.pipeline_id, |
| - result)); |
| - stream_info_map_[deferred_request.pipeline_id].pending_user_callback = |
| - send_user_callback_; |
| - send_user_callback_ = NULL; |
| - } |
| - if (result < OK) { |
| - return result; |
| + |
| + if (!send_still_on_call_stack_) { |
| + QueueUserCallback(active_send_request_->pipeline_id, |
| + active_send_request_->callback, result, FROM_HERE); |
| } |
| - if (deferred_request_queue_.empty()) { |
| + |
| + active_send_request_.reset(); |
| + |
| + if (send_still_on_call_stack_) { |
|
mmenke
2011/11/11 16:46:35
nit: Maybe add a comment here that in this case,
James Simonsen
2011/11/11 19:26:08
Done.
|
| send_next_state_ = SEND_STATE_NONE; |
| - return OK; |
| + } else if (!usable_) { |
| + send_next_state_ = SEND_STATE_EVICT_PENDING_REQUESTS; |
| + } else { |
| + send_next_state_ = SEND_STATE_START_NEXT_DEFERRED_REQUEST; |
| } |
| - send_next_state_ = SEND_STATE_NEXT_REQUEST; |
| - return OK; |
| + |
| + return result; |
| } |
| int HttpPipelinedConnectionImpl::DoEvictPendingSendRequests(int result) { |
| - send_next_state_ = SEND_STATE_NONE; |
| - while (!deferred_request_queue_.empty()) { |
| - const DeferredSendRequest& evicted_send = deferred_request_queue_.front(); |
| - if (stream_info_map_[evicted_send.pipeline_id].state != STREAM_CLOSED) { |
| - evicted_send.callback->Run(ERR_PIPELINE_EVICTION); |
| + while (!pending_send_request_queue_.empty()) { |
| + scoped_ptr<PendingSendRequest> evicted_send( |
| + pending_send_request_queue_.front()); |
| + pending_send_request_queue_.pop(); |
| + if (stream_info_map_[evicted_send->pipeline_id].state != STREAM_CLOSED) { |
| + evicted_send->callback->Run(ERR_PIPELINE_EVICTION); |
| } |
| - deferred_request_queue_.pop(); |
| } |
| + send_next_state_ = SEND_STATE_NONE; |
| return result; |
| } |
| @@ -256,18 +272,27 @@ int HttpPipelinedConnectionImpl::ReadResponseHeaders( |
| int pipeline_id, |
| OldCompletionCallback* callback) { |
| CHECK(ContainsKey(stream_info_map_, pipeline_id)); |
| - CHECK_EQ(stream_info_map_[pipeline_id].state, STREAM_SENT); |
| + CHECK_EQ(STREAM_SENT, stream_info_map_[pipeline_id].state); |
| CHECK(!stream_info_map_[pipeline_id].read_headers_callback); |
| + |
| if (!usable_) { |
| return ERR_PIPELINE_EVICTION; |
| } |
| + |
| stream_info_map_[pipeline_id].state = STREAM_READ_PENDING; |
| stream_info_map_[pipeline_id].read_headers_callback = callback; |
| - if (read_next_state_ == READ_STATE_NONE) { |
| - read_next_state_ = READ_STATE_NEXT_HEADERS; |
| + if (read_next_state_ == READ_STATE_NONE && |
| + pipeline_id == request_order_.front()) { |
| + read_next_state_ = READ_STATE_START_IMMEDIATELY; |
| return DoReadHeadersLoop(OK); |
| - } else { |
| - return ERR_IO_PENDING; |
| + } |
| + return ERR_IO_PENDING; |
| +} |
| + |
| +void HttpPipelinedConnectionImpl::StartNextDeferredRead() { |
| + if (read_next_state_ == READ_STATE_NONE) { |
| + read_next_state_ = READ_STATE_START_NEXT_DEFERRED_READ; |
| + DoReadHeadersLoop(OK); |
| } |
| } |
| @@ -277,19 +302,26 @@ int HttpPipelinedConnectionImpl::DoReadHeadersLoop(int result) { |
| ReadHeadersState state = read_next_state_; |
| read_next_state_ = READ_STATE_NONE; |
| switch (state) { |
| - case READ_STATE_NEXT_HEADERS: |
| - rv = DoReadNextHeaders(rv); |
| + case READ_STATE_START_IMMEDIATELY: |
| + rv = DoStartReadImmediately(rv); |
| break; |
| - case READ_STATE_COMPLETE: |
| + case READ_STATE_START_NEXT_DEFERRED_READ: |
| + rv = DoStartNextDeferredRead(rv); |
| + break; |
| + case READ_STATE_READ_HEADERS: |
| + rv = DoReadHeaders(rv); |
| + break; |
| + case READ_STATE_READ_HEADERS_COMPLETE: |
| rv = DoReadHeadersComplete(rv); |
| break; |
| case READ_STATE_WAITING_FOR_CLOSE: |
| - rv = DoReadWaitingForClose(rv); |
| + rv = DoReadWaitForClose(rv); |
| + read_still_on_call_stack_ = false; |
| return rv; |
|
mmenke
2011/11/11 16:46:35
nit: Think it might be nice to have a comment dra
James Simonsen
2011/11/11 19:26:08
Done.
|
| case READ_STATE_STREAM_CLOSED: |
| rv = DoReadStreamClosed(); |
| break; |
| - case READ_STATE_UNUSABLE: |
| + case READ_STATE_EVICT_PENDING_READS: |
| rv = DoEvictPendingReadHeaders(rv); |
| break; |
| case READ_STATE_NONE: |
| @@ -300,139 +332,123 @@ int HttpPipelinedConnectionImpl::DoReadHeadersLoop(int result) { |
| break; |
| } |
| } while (rv != ERR_IO_PENDING && read_next_state_ != READ_STATE_NONE); |
| + read_still_on_call_stack_ = false; |
| return rv; |
| } |
| void HttpPipelinedConnectionImpl::OnReadIOCallback(int result) { |
| - CHECK(read_user_callback_); |
| DoReadHeadersLoop(result); |
| } |
| -int HttpPipelinedConnectionImpl::DoReadNextHeaders(int result) { |
| - CHECK(!request_order_.empty()); |
| - int pipeline_id = request_order_.front(); |
| - CHECK(ContainsKey(stream_info_map_, pipeline_id)); |
| - if (stream_info_map_[pipeline_id].state == STREAM_CLOSED) { |
| - // Since nobody will read whatever data is on the pipeline associated with |
| - // this closed request, we must shut down the rest of the pipeline. |
| - read_next_state_ = READ_STATE_UNUSABLE; |
| +int HttpPipelinedConnectionImpl::DoStartReadImmediately(int result) { |
| + read_still_on_call_stack_ = true; |
| + read_next_state_ = READ_STATE_READ_HEADERS; |
| + active_read_id_ = request_order_.front(); |
| + request_order_.pop(); |
| + return OK; |
| +} |
| + |
| +int HttpPipelinedConnectionImpl::DoStartNextDeferredRead(int result) { |
| + if (request_order_.empty()) { |
| + read_next_state_ = READ_STATE_NONE; |
| return OK; |
| } |
| - if (stream_info_map_[pipeline_id].read_headers_callback == NULL) { |
| - return ERR_IO_PENDING; |
| - } |
| - CHECK(stream_info_map_[pipeline_id].parser.get()); |
| - if (result == ERR_IO_PENDING) { |
| - CHECK_EQ(stream_info_map_[pipeline_id].state, STREAM_ACTIVE); |
| - } else { |
| - CHECK_EQ(stream_info_map_[pipeline_id].state, STREAM_READ_PENDING); |
| - stream_info_map_[pipeline_id].state = STREAM_ACTIVE; |
| - } |
| + int next_id = request_order_.front(); |
| + CHECK(ContainsKey(stream_info_map_, next_id)); |
| + switch (stream_info_map_[next_id].state) { |
| + case STREAM_READ_PENDING: |
| + read_next_state_ = READ_STATE_READ_HEADERS; |
| + active_read_id_ = next_id; |
| + request_order_.pop(); |
| + break; |
| - int rv = stream_info_map_[pipeline_id].parser->ReadResponseHeaders( |
| - &read_io_callback_); |
| - if (rv == ERR_IO_PENDING) { |
| - read_next_state_ = READ_STATE_COMPLETE; |
| - read_user_callback_ = stream_info_map_[pipeline_id].read_headers_callback; |
| - } else if (rv < OK) { |
| - read_next_state_ = READ_STATE_WAITING_FOR_CLOSE; |
| - if (rv == ERR_SOCKET_NOT_CONNECTED && completed_one_request_) |
| - rv = ERR_PIPELINE_EVICTION; |
| - } else { |
| - CHECK_LE(OK, rv); |
| - read_next_state_ = READ_STATE_WAITING_FOR_CLOSE; |
| - } |
| + case STREAM_CLOSED: |
| + // Since nobody will read whatever data is on the pipeline associated with |
| + // this closed request, we must shut down the rest of the pipeline. |
| + read_next_state_ = READ_STATE_EVICT_PENDING_READS; |
| + break; |
| - // |result| == ERR_IO_PENDING means this function was *not* called on the same |
| - // stack as ReadResponseHeaders(). That means we returned ERR_IO_PENDING to |
| - // ReadResponseHeaders() earlier and now need to invoke its callback. |
| - if (rv != ERR_IO_PENDING && result == ERR_IO_PENDING) { |
| - read_next_state_ = READ_STATE_WAITING_FOR_CLOSE; |
| - read_user_callback_ = stream_info_map_[pipeline_id].read_headers_callback; |
| - stream_info_map_[pipeline_id].pending_user_callback = read_user_callback_; |
| - MessageLoop::current()->PostTask( |
| - FROM_HERE, |
| - method_factory_.NewRunnableMethod( |
| - &HttpPipelinedConnectionImpl::FireUserCallback, |
| - pipeline_id, |
| - rv)); |
| + case STREAM_SENT: |
| + read_next_state_ = READ_STATE_NONE; |
| + break; |
| + |
| + default: |
| + NOTREACHED() << "Unexpected read state: " |
| + << stream_info_map_[next_id].state; |
| } |
| + |
| + return OK; |
| +} |
| + |
| +int HttpPipelinedConnectionImpl::DoReadHeaders(int result) { |
| + CHECK(active_read_id_); |
| + CHECK(ContainsKey(stream_info_map_, active_read_id_)); |
| + stream_info_map_[active_read_id_].state = STREAM_ACTIVE; |
| + int rv = stream_info_map_[active_read_id_].parser->ReadResponseHeaders( |
| + &read_io_callback_); |
| + read_next_state_ = READ_STATE_READ_HEADERS_COMPLETE; |
| return rv; |
| } |
| int HttpPipelinedConnectionImpl::DoReadHeadersComplete(int result) { |
| + CHECK(active_read_id_); |
| + CHECK(ContainsKey(stream_info_map_, active_read_id_)); |
| + |
| read_next_state_ = READ_STATE_WAITING_FOR_CLOSE; |
| - if (read_user_callback_) { |
| - int pipeline_id = request_order_.front(); |
| - MessageLoop::current()->PostTask( |
| - FROM_HERE, |
| - method_factory_.NewRunnableMethod( |
| - &HttpPipelinedConnectionImpl::FireUserCallback, |
| - pipeline_id, |
| - result)); |
| - stream_info_map_[pipeline_id].pending_user_callback = read_user_callback_; |
| - read_user_callback_ = NULL; |
| + if (result < OK) { |
| + if (result == ERR_SOCKET_NOT_CONNECTED && completed_one_request_) { |
| + result = ERR_PIPELINE_EVICTION; |
| + } |
| + usable_ = false; |
| + } |
| + |
| + if (!read_still_on_call_stack_) { |
| + QueueUserCallback(active_read_id_, |
| + stream_info_map_[active_read_id_].read_headers_callback, |
| + result, FROM_HERE); |
| } |
| + |
| return result; |
| } |
| -int HttpPipelinedConnectionImpl::DoReadWaitingForClose(int result) { |
| +int HttpPipelinedConnectionImpl::DoReadWaitForClose(int result) { |
| read_next_state_ = READ_STATE_WAITING_FOR_CLOSE; |
| return result; |
| } |
| int HttpPipelinedConnectionImpl::DoReadStreamClosed() { |
| - CHECK(!request_order_.empty()); |
| - int pipeline_id = request_order_.front(); |
| - CHECK(ContainsKey(stream_info_map_, pipeline_id)); |
| - CHECK_EQ(stream_info_map_[pipeline_id].state, STREAM_CLOSED); |
| - CHECK(stream_info_map_[pipeline_id].read_headers_callback); |
| - stream_info_map_[pipeline_id].read_headers_callback = NULL; |
| - request_order_.pop(); |
| + CHECK(active_read_id_); |
| + CHECK(ContainsKey(stream_info_map_, active_read_id_)); |
| + CHECK_EQ(stream_info_map_[active_read_id_].state, STREAM_CLOSED); |
| + active_read_id_ = 0; |
| if (!usable_) { |
| - read_next_state_ = READ_STATE_UNUSABLE; |
| - return OK; |
| - } else { |
| - completed_one_request_ = true; |
| - if (!request_order_.empty()) { |
| - int next_pipeline_id = request_order_.front(); |
| - CHECK(ContainsKey(stream_info_map_, next_pipeline_id)); |
| - if (stream_info_map_[next_pipeline_id].read_headers_callback) { |
| - stream_info_map_[next_pipeline_id].state = STREAM_ACTIVE; |
| - read_next_state_ = READ_STATE_NEXT_HEADERS; |
| - MessageLoop::current()->PostTask( |
| - FROM_HERE, |
| - method_factory_.NewRunnableMethod( |
| - &HttpPipelinedConnectionImpl::DoReadHeadersLoop, |
| - ERR_IO_PENDING)); |
| - return ERR_IO_PENDING; // Wait for the task to fire. |
| - } |
| - } |
| - read_next_state_ = READ_STATE_NONE; |
| + read_next_state_ = READ_STATE_EVICT_PENDING_READS; |
| return OK; |
| } |
| + completed_one_request_ = true; |
| + MessageLoop::current()->PostTask( |
| + FROM_HERE, |
| + method_factory_.NewRunnableMethod( |
| + &HttpPipelinedConnectionImpl::StartNextDeferredRead)); |
| + read_next_state_ = READ_STATE_NONE; |
| + return OK; |
| } |
| int HttpPipelinedConnectionImpl::DoEvictPendingReadHeaders(int result) { |
| while (!request_order_.empty()) { |
| int evicted_id = request_order_.front(); |
| request_order_.pop(); |
| - if (!ContainsKey(stream_info_map_, evicted_id) || |
| - (stream_info_map_[evicted_id].read_headers_callback == NULL)) { |
| + if (!ContainsKey(stream_info_map_, evicted_id)) { |
| continue; |
| } |
| - if (stream_info_map_[evicted_id].state != STREAM_CLOSED) { |
| - stream_info_map_[evicted_id].pending_user_callback = |
| - stream_info_map_[evicted_id].read_headers_callback; |
| - MessageLoop::current()->PostTask( |
| - FROM_HERE, |
| - method_factory_.NewRunnableMethod( |
| - &HttpPipelinedConnectionImpl::FireUserCallback, |
| - evicted_id, |
| - ERR_PIPELINE_EVICTION)); |
| + if (stream_info_map_[evicted_id].state == STREAM_READ_PENDING) { |
| + stream_info_map_[evicted_id].state = STREAM_READ_EVICTED; |
| + QueueUserCallback(evicted_id, |
| + stream_info_map_[evicted_id].read_headers_callback, |
| + ERR_PIPELINE_EVICTION, |
| + FROM_HERE); |
| } |
| - stream_info_map_[evicted_id].read_headers_callback = NULL; |
| } |
| read_next_state_ = READ_STATE_NONE; |
| return result; |
| @@ -453,8 +469,8 @@ void HttpPipelinedConnectionImpl::Close(int pipeline_id, |
| case STREAM_SENDING: |
| usable_ = false; |
| stream_info_map_[pipeline_id].state = STREAM_CLOSED; |
| - send_user_callback_ = NULL; |
| - send_next_state_ = SEND_STATE_UNUSABLE; |
| + active_send_request_.reset(); |
| + send_next_state_ = SEND_STATE_EVICT_PENDING_REQUESTS; |
| DoSendRequestLoop(OK); |
| break; |
| @@ -462,9 +478,10 @@ void HttpPipelinedConnectionImpl::Close(int pipeline_id, |
| case STREAM_READ_PENDING: |
| usable_ = false; |
| stream_info_map_[pipeline_id].state = STREAM_CLOSED; |
| - stream_info_map_[pipeline_id].read_headers_callback = NULL; |
| - if (read_next_state_ == READ_STATE_NONE) { |
| - read_next_state_ = READ_STATE_UNUSABLE; |
| + if (!request_order_.empty() && |
| + pipeline_id == request_order_.front() && |
| + read_next_state_ == READ_STATE_NONE) { |
| + read_next_state_ = READ_STATE_EVICT_PENDING_READS; |
| DoReadHeadersLoop(OK); |
| } |
| break; |
| @@ -475,10 +492,13 @@ void HttpPipelinedConnectionImpl::Close(int pipeline_id, |
| usable_ = false; |
| } |
| read_next_state_ = READ_STATE_STREAM_CLOSED; |
| - read_user_callback_ = NULL; |
| DoReadHeadersLoop(OK); |
| break; |
| + case STREAM_READ_EVICTED: |
| + stream_info_map_[pipeline_id].state = STREAM_CLOSED; |
| + break; |
| + |
| case STREAM_CLOSED: |
| case STREAM_UNUSED: |
| // TODO(simonjam): Why is Close() sometimes called twice? |
| @@ -496,8 +516,7 @@ int HttpPipelinedConnectionImpl::ReadResponseBody( |
| int buf_len, |
| OldCompletionCallback* callback) { |
| CHECK(ContainsKey(stream_info_map_, pipeline_id)); |
| - CHECK(!request_order_.empty()); |
| - CHECK_EQ(pipeline_id, request_order_.front()); |
| + CHECK_EQ(active_read_id_, pipeline_id); |
| CHECK(stream_info_map_[pipeline_id].parser.get()); |
| return stream_info_map_[pipeline_id].parser->ReadResponseBody( |
| buf, buf_len, callback); |
| @@ -567,10 +586,29 @@ void HttpPipelinedConnectionImpl::GetSSLCertRequestInfo( |
| cert_request_info); |
| } |
| +void HttpPipelinedConnectionImpl::QueueUserCallback( |
| + int pipeline_id, |
| + OldCompletionCallback* callback, |
| + int rv, |
| + const tracked_objects::Location& from_here) { |
| + CHECK(!stream_info_map_[pipeline_id].pending_user_callback); |
| + stream_info_map_[pipeline_id].pending_user_callback = callback; |
| + MessageLoop::current()->PostTask( |
| + from_here, |
| + method_factory_.NewRunnableMethod( |
| + &HttpPipelinedConnectionImpl::FireUserCallback, |
| + pipeline_id, |
| + rv)); |
| +} |
| + |
| void HttpPipelinedConnectionImpl::FireUserCallback(int pipeline_id, |
| int result) { |
| if (ContainsKey(stream_info_map_, pipeline_id)) { |
| - stream_info_map_[pipeline_id].pending_user_callback->Run(result); |
| + CHECK(stream_info_map_[pipeline_id].pending_user_callback); |
| + OldCompletionCallback* callback = |
| + stream_info_map_[pipeline_id].pending_user_callback; |
| + stream_info_map_[pipeline_id].pending_user_callback = NULL; |
| + callback->Run(result); |
| } |
| } |
| @@ -602,14 +640,15 @@ bool HttpPipelinedConnectionImpl::was_npn_negotiated() const { |
| return was_npn_negotiated_; |
| } |
| -HttpPipelinedConnectionImpl::DeferredSendRequest::DeferredSendRequest() { |
| +HttpPipelinedConnectionImpl::PendingSendRequest::PendingSendRequest() { |
| } |
| -HttpPipelinedConnectionImpl::DeferredSendRequest::~DeferredSendRequest() { |
| +HttpPipelinedConnectionImpl::PendingSendRequest::~PendingSendRequest() { |
| } |
| HttpPipelinedConnectionImpl::StreamInfo::StreamInfo() |
| : read_headers_callback(NULL), |
| + pending_user_callback(NULL), |
| state(STREAM_CREATED) { |
| } |