Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(895)

Side by Side Diff: net/http/http_pipelined_connection_impl.cc

Issue 275953002: Remove HTTP pipelining support. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix line endings Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/http/http_pipelined_connection_impl.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/stl_util.h"
11 #include "base/values.h"
12 #include "net/base/io_buffer.h"
13 #include "net/http/http_pipelined_stream.h"
14 #include "net/http/http_request_info.h"
15 #include "net/http/http_response_body_drainer.h"
16 #include "net/http/http_response_headers.h"
17 #include "net/http/http_stream_parser.h"
18 #include "net/http/http_version.h"
19 #include "net/socket/client_socket_handle.h"
20
21 namespace net {
22
23 namespace {
24
25 base::Value* NetLogReceivedHeadersCallback(const NetLog::Source& source,
26 const std::string* feedback,
27 NetLog::LogLevel /* log_level */) {
28 base::DictionaryValue* dict = new base::DictionaryValue;
29 source.AddToEventParameters(dict);
30 dict->SetString("feedback", *feedback);
31 return dict;
32 }
33
34 base::Value* NetLogStreamClosedCallback(const NetLog::Source& source,
35 bool not_reusable,
36 NetLog::LogLevel /* log_level */) {
37 base::DictionaryValue* dict = new base::DictionaryValue;
38 source.AddToEventParameters(dict);
39 dict->SetBoolean("not_reusable", not_reusable);
40 return dict;
41 }
42
43 base::Value* NetLogHostPortPairCallback(const HostPortPair* host_port_pair,
44 NetLog::LogLevel /* log_level */) {
45 base::DictionaryValue* dict = new base::DictionaryValue;
46 dict->SetString("host_and_port", host_port_pair->ToString());
47 return dict;
48 }
49
50 } // anonymous namespace
51
52 HttpPipelinedConnection*
53 HttpPipelinedConnectionImpl::Factory::CreateNewPipeline(
54 ClientSocketHandle* connection,
55 HttpPipelinedConnection::Delegate* delegate,
56 const HostPortPair& origin,
57 const SSLConfig& used_ssl_config,
58 const ProxyInfo& used_proxy_info,
59 const BoundNetLog& net_log,
60 bool was_npn_negotiated,
61 NextProto protocol_negotiated) {
62 return new HttpPipelinedConnectionImpl(connection, delegate, origin,
63 used_ssl_config, used_proxy_info,
64 net_log, was_npn_negotiated,
65 protocol_negotiated);
66 }
67
68 HttpPipelinedConnectionImpl::HttpPipelinedConnectionImpl(
69 ClientSocketHandle* connection,
70 HttpPipelinedConnection::Delegate* delegate,
71 const HostPortPair& origin,
72 const SSLConfig& used_ssl_config,
73 const ProxyInfo& used_proxy_info,
74 const BoundNetLog& net_log,
75 bool was_npn_negotiated,
76 NextProto protocol_negotiated)
77 : delegate_(delegate),
78 connection_(connection),
79 used_ssl_config_(used_ssl_config),
80 used_proxy_info_(used_proxy_info),
81 net_log_(BoundNetLog::Make(net_log.net_log(),
82 NetLog::SOURCE_HTTP_PIPELINED_CONNECTION)),
83 was_npn_negotiated_(was_npn_negotiated),
84 protocol_negotiated_(protocol_negotiated),
85 read_buf_(new GrowableIOBuffer()),
86 next_pipeline_id_(1),
87 active_(false),
88 usable_(true),
89 completed_one_request_(false),
90 weak_factory_(this),
91 send_next_state_(SEND_STATE_NONE),
92 send_still_on_call_stack_(false),
93 read_next_state_(READ_STATE_NONE),
94 active_read_id_(0),
95 read_still_on_call_stack_(false) {
96 CHECK(connection_.get());
97 net_log_.BeginEvent(
98 NetLog::TYPE_HTTP_PIPELINED_CONNECTION,
99 base::Bind(&NetLogHostPortPairCallback, &origin));
100 }
101
102 HttpPipelinedConnectionImpl::~HttpPipelinedConnectionImpl() {
103 CHECK_EQ(depth(), 0);
104 CHECK(stream_info_map_.empty());
105 CHECK(pending_send_request_queue_.empty());
106 CHECK(request_order_.empty());
107 CHECK_EQ(send_next_state_, SEND_STATE_NONE);
108 CHECK_EQ(read_next_state_, READ_STATE_NONE);
109 CHECK(!active_send_request_.get());
110 CHECK(!active_read_id_);
111 if (!usable_) {
112 connection_->socket()->Disconnect();
113 }
114 connection_->Reset();
115 net_log_.EndEvent(NetLog::TYPE_HTTP_PIPELINED_CONNECTION);
116 }
117
118 HttpPipelinedStream* HttpPipelinedConnectionImpl::CreateNewStream() {
119 int pipeline_id = next_pipeline_id_++;
120 CHECK(pipeline_id);
121 HttpPipelinedStream* stream = new HttpPipelinedStream(this, pipeline_id);
122 stream_info_map_.insert(std::make_pair(pipeline_id, StreamInfo()));
123 return stream;
124 }
125
126 void HttpPipelinedConnectionImpl::InitializeParser(
127 int pipeline_id,
128 const HttpRequestInfo* request,
129 const BoundNetLog& net_log) {
130 CHECK(ContainsKey(stream_info_map_, pipeline_id));
131 CHECK(!stream_info_map_[pipeline_id].parser.get());
132 stream_info_map_[pipeline_id].state = STREAM_BOUND;
133 stream_info_map_[pipeline_id].parser.reset(new HttpStreamParser(
134 connection_.get(), request, read_buf_.get(), net_log));
135 stream_info_map_[pipeline_id].source = net_log.source();
136
137 // In case our first stream doesn't SendRequest() immediately, we should still
138 // allow others to use this pipeline.
139 if (pipeline_id == 1) {
140 base::MessageLoop::current()->PostTask(
141 FROM_HERE,
142 base::Bind(&HttpPipelinedConnectionImpl::ActivatePipeline,
143 weak_factory_.GetWeakPtr()));
144 }
145 }
146
147 void HttpPipelinedConnectionImpl::ActivatePipeline() {
148 if (!active_) {
149 active_ = true;
150 delegate_->OnPipelineHasCapacity(this);
151 }
152 }
153
154 void HttpPipelinedConnectionImpl::OnStreamDeleted(int pipeline_id) {
155 CHECK(ContainsKey(stream_info_map_, pipeline_id));
156 Close(pipeline_id, false);
157
158 if (stream_info_map_[pipeline_id].state != STREAM_CREATED &&
159 stream_info_map_[pipeline_id].state != STREAM_UNUSED) {
160 CHECK_EQ(stream_info_map_[pipeline_id].state, STREAM_CLOSED);
161 CHECK(stream_info_map_[pipeline_id].parser.get());
162 stream_info_map_[pipeline_id].parser.reset();
163 }
164 CHECK(!stream_info_map_[pipeline_id].parser.get());
165 stream_info_map_.erase(pipeline_id);
166
167 delegate_->OnPipelineHasCapacity(this);
168 }
169
170 int HttpPipelinedConnectionImpl::SendRequest(
171 int pipeline_id,
172 const std::string& request_line,
173 const HttpRequestHeaders& headers,
174 HttpResponseInfo* response,
175 const CompletionCallback& callback) {
176 CHECK(ContainsKey(stream_info_map_, pipeline_id));
177 CHECK_EQ(stream_info_map_[pipeline_id].state, STREAM_BOUND);
178 if (!usable_) {
179 return ERR_PIPELINE_EVICTION;
180 }
181
182 PendingSendRequest* send_request = new PendingSendRequest;
183 send_request->pipeline_id = pipeline_id;
184 send_request->request_line = request_line;
185 send_request->headers = headers;
186 send_request->response = response;
187 send_request->callback = callback;
188 pending_send_request_queue_.push(send_request);
189
190 int rv;
191 if (send_next_state_ == SEND_STATE_NONE) {
192 send_next_state_ = SEND_STATE_START_IMMEDIATELY;
193 rv = DoSendRequestLoop(OK);
194 } else {
195 rv = ERR_IO_PENDING;
196 }
197 ActivatePipeline();
198 return rv;
199 }
200
201 int HttpPipelinedConnectionImpl::DoSendRequestLoop(int result) {
202 int rv = result;
203 do {
204 SendRequestState state = send_next_state_;
205 send_next_state_ = SEND_STATE_NONE;
206 switch (state) {
207 case SEND_STATE_START_IMMEDIATELY:
208 rv = DoStartRequestImmediately(rv);
209 break;
210 case SEND_STATE_START_NEXT_DEFERRED_REQUEST:
211 rv = DoStartNextDeferredRequest(rv);
212 break;
213 case SEND_STATE_SEND_ACTIVE_REQUEST:
214 rv = DoSendActiveRequest(rv);
215 break;
216 case SEND_STATE_COMPLETE:
217 rv = DoSendComplete(rv);
218 break;
219 case SEND_STATE_EVICT_PENDING_REQUESTS:
220 rv = DoEvictPendingSendRequests(rv);
221 break;
222 default:
223 CHECK(false) << "bad send state: " << state;
224 rv = ERR_FAILED;
225 break;
226 }
227 } while (rv != ERR_IO_PENDING && send_next_state_ != SEND_STATE_NONE);
228 send_still_on_call_stack_ = false;
229 return rv;
230 }
231
232 void HttpPipelinedConnectionImpl::OnSendIOCallback(int result) {
233 CHECK(active_send_request_.get());
234 DoSendRequestLoop(result);
235 }
236
237 int HttpPipelinedConnectionImpl::DoStartRequestImmediately(int result) {
238 CHECK(!active_send_request_.get());
239 CHECK_EQ(static_cast<size_t>(1), pending_send_request_queue_.size());
240 // If SendRequest() completes synchronously, then we need to return the value
241 // directly to the caller. |send_still_on_call_stack_| will track this.
242 // Otherwise, asynchronous completions will notify the caller via callback.
243 send_still_on_call_stack_ = true;
244 active_send_request_.reset(pending_send_request_queue_.front());
245 pending_send_request_queue_.pop();
246 send_next_state_ = SEND_STATE_SEND_ACTIVE_REQUEST;
247 return OK;
248 }
249
250 int HttpPipelinedConnectionImpl::DoStartNextDeferredRequest(int result) {
251 CHECK(!send_still_on_call_stack_);
252 CHECK(!active_send_request_.get());
253
254 while (!pending_send_request_queue_.empty()) {
255 scoped_ptr<PendingSendRequest> next_request(
256 pending_send_request_queue_.front());
257 pending_send_request_queue_.pop();
258 CHECK(ContainsKey(stream_info_map_, next_request->pipeline_id));
259 if (stream_info_map_[next_request->pipeline_id].state != STREAM_CLOSED) {
260 active_send_request_.reset(next_request.release());
261 send_next_state_ = SEND_STATE_SEND_ACTIVE_REQUEST;
262 return OK;
263 }
264 }
265
266 send_next_state_ = SEND_STATE_NONE;
267 return OK;
268 }
269
270 int HttpPipelinedConnectionImpl::DoSendActiveRequest(int result) {
271 CHECK(stream_info_map_[active_send_request_->pipeline_id].parser.get());
272 int rv = stream_info_map_[active_send_request_->pipeline_id].parser->
273 SendRequest(active_send_request_->request_line,
274 active_send_request_->headers,
275 active_send_request_->response,
276 base::Bind(&HttpPipelinedConnectionImpl::OnSendIOCallback,
277 base::Unretained(this)));
278 stream_info_map_[active_send_request_->pipeline_id].state = STREAM_SENDING;
279 send_next_state_ = SEND_STATE_COMPLETE;
280 return rv;
281 }
282
283 int HttpPipelinedConnectionImpl::DoSendComplete(int result) {
284 CHECK(active_send_request_.get());
285 CHECK_EQ(STREAM_SENDING,
286 stream_info_map_[active_send_request_->pipeline_id].state);
287
288 request_order_.push(active_send_request_->pipeline_id);
289 stream_info_map_[active_send_request_->pipeline_id].state = STREAM_SENT;
290 net_log_.AddEvent(
291 NetLog::TYPE_HTTP_PIPELINED_CONNECTION_SENT_REQUEST,
292 stream_info_map_[active_send_request_->pipeline_id].source.
293 ToEventParametersCallback());
294
295 if (result == ERR_SOCKET_NOT_CONNECTED && completed_one_request_) {
296 result = ERR_PIPELINE_EVICTION;
297 }
298 if (result < OK) {
299 usable_ = false;
300 }
301
302 if (!send_still_on_call_stack_) {
303 QueueUserCallback(active_send_request_->pipeline_id,
304 active_send_request_->callback, result, FROM_HERE);
305 }
306
307 active_send_request_.reset();
308
309 if (send_still_on_call_stack_) {
310 // It should be impossible for another request to appear on the queue while
311 // this send was on the call stack.
312 CHECK(pending_send_request_queue_.empty());
313 send_next_state_ = SEND_STATE_NONE;
314 } else if (!usable_) {
315 send_next_state_ = SEND_STATE_EVICT_PENDING_REQUESTS;
316 } else {
317 send_next_state_ = SEND_STATE_START_NEXT_DEFERRED_REQUEST;
318 }
319
320 return result;
321 }
322
323 int HttpPipelinedConnectionImpl::DoEvictPendingSendRequests(int result) {
324 while (!pending_send_request_queue_.empty()) {
325 scoped_ptr<PendingSendRequest> evicted_send(
326 pending_send_request_queue_.front());
327 pending_send_request_queue_.pop();
328 if (ContainsKey(stream_info_map_, evicted_send->pipeline_id) &&
329 stream_info_map_[evicted_send->pipeline_id].state != STREAM_CLOSED) {
330 evicted_send->callback.Run(ERR_PIPELINE_EVICTION);
331 }
332 }
333 send_next_state_ = SEND_STATE_NONE;
334 return result;
335 }
336
337 int HttpPipelinedConnectionImpl::ReadResponseHeaders(
338 int pipeline_id, const CompletionCallback& callback) {
339 CHECK(ContainsKey(stream_info_map_, pipeline_id));
340 CHECK_EQ(STREAM_SENT, stream_info_map_[pipeline_id].state);
341 CHECK(stream_info_map_[pipeline_id].read_headers_callback.is_null());
342
343 if (!usable_)
344 return ERR_PIPELINE_EVICTION;
345
346 stream_info_map_[pipeline_id].state = STREAM_READ_PENDING;
347 stream_info_map_[pipeline_id].read_headers_callback = callback;
348 if (read_next_state_ == READ_STATE_NONE &&
349 pipeline_id == request_order_.front()) {
350 read_next_state_ = READ_STATE_START_IMMEDIATELY;
351 return DoReadHeadersLoop(OK);
352 }
353 return ERR_IO_PENDING;
354 }
355
356 void HttpPipelinedConnectionImpl::StartNextDeferredRead() {
357 if (read_next_state_ == READ_STATE_NONE) {
358 read_next_state_ = READ_STATE_START_NEXT_DEFERRED_READ;
359 DoReadHeadersLoop(OK);
360 }
361 }
362
363 int HttpPipelinedConnectionImpl::DoReadHeadersLoop(int result) {
364 int rv = result;
365 do {
366 ReadHeadersState state = read_next_state_;
367 read_next_state_ = READ_STATE_NONE;
368 switch (state) {
369 case READ_STATE_START_IMMEDIATELY:
370 rv = DoStartReadImmediately(rv);
371 break;
372 case READ_STATE_START_NEXT_DEFERRED_READ:
373 rv = DoStartNextDeferredRead(rv);
374 break;
375 case READ_STATE_READ_HEADERS:
376 rv = DoReadHeaders(rv);
377 break;
378 case READ_STATE_READ_HEADERS_COMPLETE:
379 rv = DoReadHeadersComplete(rv);
380 break;
381 case READ_STATE_WAITING_FOR_CLOSE:
382 // This is a holding state. We return instead of continuing to run hte
383 // loop. The state will advance when the stream calls Close().
384 rv = DoReadWaitForClose(rv);
385 read_still_on_call_stack_ = false;
386 return rv;
387 case READ_STATE_STREAM_CLOSED:
388 rv = DoReadStreamClosed();
389 break;
390 case READ_STATE_EVICT_PENDING_READS:
391 rv = DoEvictPendingReadHeaders(rv);
392 break;
393 case READ_STATE_NONE:
394 break;
395 default:
396 CHECK(false) << "bad read state";
397 rv = ERR_FAILED;
398 break;
399 }
400 } while (rv != ERR_IO_PENDING && read_next_state_ != READ_STATE_NONE);
401 read_still_on_call_stack_ = false;
402 return rv;
403 }
404
405 void HttpPipelinedConnectionImpl::OnReadIOCallback(int result) {
406 DoReadHeadersLoop(result);
407 }
408
409 int HttpPipelinedConnectionImpl::DoStartReadImmediately(int result) {
410 CHECK(!active_read_id_);
411 CHECK(!read_still_on_call_stack_);
412 CHECK(!request_order_.empty());
413 // If ReadResponseHeaders() completes synchronously, then we need to return
414 // the value directly to the caller. |read_still_on_call_stack_| will track
415 // this. Otherwise, asynchronous completions will notify the caller via
416 // callback.
417 read_still_on_call_stack_ = true;
418 read_next_state_ = READ_STATE_READ_HEADERS;
419 active_read_id_ = request_order_.front();
420 request_order_.pop();
421 return OK;
422 }
423
424 int HttpPipelinedConnectionImpl::DoStartNextDeferredRead(int result) {
425 CHECK(!active_read_id_);
426 CHECK(!read_still_on_call_stack_);
427
428 if (request_order_.empty()) {
429 read_next_state_ = READ_STATE_NONE;
430 return OK;
431 }
432
433 int next_id = request_order_.front();
434 CHECK(ContainsKey(stream_info_map_, next_id));
435 switch (stream_info_map_[next_id].state) {
436 case STREAM_READ_PENDING:
437 read_next_state_ = READ_STATE_READ_HEADERS;
438 active_read_id_ = next_id;
439 request_order_.pop();
440 break;
441
442 case STREAM_CLOSED:
443 // Since nobody will read whatever data is on the pipeline associated with
444 // this closed request, we must shut down the rest of the pipeline.
445 read_next_state_ = READ_STATE_EVICT_PENDING_READS;
446 break;
447
448 case STREAM_SENT:
449 read_next_state_ = READ_STATE_NONE;
450 break;
451
452 default:
453 CHECK(false) << "Unexpected read state: "
454 << stream_info_map_[next_id].state;
455 }
456
457 return OK;
458 }
459
460 int HttpPipelinedConnectionImpl::DoReadHeaders(int result) {
461 CHECK(active_read_id_);
462 CHECK(ContainsKey(stream_info_map_, active_read_id_));
463 CHECK_EQ(STREAM_READ_PENDING, stream_info_map_[active_read_id_].state);
464 stream_info_map_[active_read_id_].state = STREAM_ACTIVE;
465 int rv = stream_info_map_[active_read_id_].parser->ReadResponseHeaders(
466 base::Bind(&HttpPipelinedConnectionImpl::OnReadIOCallback,
467 base::Unretained(this)));
468 read_next_state_ = READ_STATE_READ_HEADERS_COMPLETE;
469 return rv;
470 }
471
472 int HttpPipelinedConnectionImpl::DoReadHeadersComplete(int result) {
473 CHECK(active_read_id_);
474 CHECK(ContainsKey(stream_info_map_, active_read_id_));
475 CHECK_EQ(STREAM_ACTIVE, stream_info_map_[active_read_id_].state);
476
477 read_next_state_ = READ_STATE_WAITING_FOR_CLOSE;
478 if (result < OK) {
479 if (completed_one_request_ &&
480 (result == ERR_CONNECTION_CLOSED ||
481 result == ERR_EMPTY_RESPONSE ||
482 result == ERR_SOCKET_NOT_CONNECTED)) {
483 // These usually indicate that pipelining failed on the server side. In
484 // that case, we should retry without pipelining.
485 result = ERR_PIPELINE_EVICTION;
486 }
487 usable_ = false;
488 }
489
490 CheckHeadersForPipelineCompatibility(active_read_id_, result);
491
492 if (!read_still_on_call_stack_) {
493 QueueUserCallback(active_read_id_,
494 stream_info_map_[active_read_id_].read_headers_callback,
495 result, FROM_HERE);
496 }
497
498 return result;
499 }
500
501 int HttpPipelinedConnectionImpl::DoReadWaitForClose(int result) {
502 read_next_state_ = READ_STATE_WAITING_FOR_CLOSE;
503 return result;
504 }
505
506 int HttpPipelinedConnectionImpl::DoReadStreamClosed() {
507 CHECK(active_read_id_);
508 CHECK(ContainsKey(stream_info_map_, active_read_id_));
509 CHECK_EQ(stream_info_map_[active_read_id_].state, STREAM_CLOSED);
510 active_read_id_ = 0;
511 if (!usable_) {
512 // TODO(simonjam): Don't wait this long to evict.
513 read_next_state_ = READ_STATE_EVICT_PENDING_READS;
514 return OK;
515 }
516 completed_one_request_ = true;
517 base::MessageLoop::current()->PostTask(
518 FROM_HERE,
519 base::Bind(&HttpPipelinedConnectionImpl::StartNextDeferredRead,
520 weak_factory_.GetWeakPtr()));
521 read_next_state_ = READ_STATE_NONE;
522 return OK;
523 }
524
525 int HttpPipelinedConnectionImpl::DoEvictPendingReadHeaders(int result) {
526 while (!request_order_.empty()) {
527 int evicted_id = request_order_.front();
528 request_order_.pop();
529 if (!ContainsKey(stream_info_map_, evicted_id)) {
530 continue;
531 }
532 if (stream_info_map_[evicted_id].state == STREAM_READ_PENDING) {
533 stream_info_map_[evicted_id].state = STREAM_READ_EVICTED;
534 stream_info_map_[evicted_id].read_headers_callback.Run(
535 ERR_PIPELINE_EVICTION);
536 }
537 }
538 read_next_state_ = READ_STATE_NONE;
539 return result;
540 }
541
542 void HttpPipelinedConnectionImpl::Close(int pipeline_id,
543 bool not_reusable) {
544 CHECK(ContainsKey(stream_info_map_, pipeline_id));
545 net_log_.AddEvent(
546 NetLog::TYPE_HTTP_PIPELINED_CONNECTION_STREAM_CLOSED,
547 base::Bind(&NetLogStreamClosedCallback,
548 stream_info_map_[pipeline_id].source, not_reusable));
549 switch (stream_info_map_[pipeline_id].state) {
550 case STREAM_CREATED:
551 stream_info_map_[pipeline_id].state = STREAM_UNUSED;
552 break;
553
554 case STREAM_BOUND:
555 stream_info_map_[pipeline_id].state = STREAM_CLOSED;
556 break;
557
558 case STREAM_SENDING:
559 usable_ = false;
560 stream_info_map_[pipeline_id].state = STREAM_CLOSED;
561 active_send_request_.reset();
562 send_next_state_ = SEND_STATE_EVICT_PENDING_REQUESTS;
563 DoSendRequestLoop(OK);
564 break;
565
566 case STREAM_SENT:
567 case STREAM_READ_PENDING:
568 usable_ = false;
569 stream_info_map_[pipeline_id].state = STREAM_CLOSED;
570 if (!request_order_.empty() &&
571 pipeline_id == request_order_.front() &&
572 read_next_state_ == READ_STATE_NONE) {
573 read_next_state_ = READ_STATE_EVICT_PENDING_READS;
574 DoReadHeadersLoop(OK);
575 }
576 break;
577
578 case STREAM_ACTIVE:
579 stream_info_map_[pipeline_id].state = STREAM_CLOSED;
580 if (not_reusable) {
581 usable_ = false;
582 }
583 read_next_state_ = READ_STATE_STREAM_CLOSED;
584 DoReadHeadersLoop(OK);
585 break;
586
587 case STREAM_READ_EVICTED:
588 stream_info_map_[pipeline_id].state = STREAM_CLOSED;
589 break;
590
591 case STREAM_CLOSED:
592 case STREAM_UNUSED:
593 // TODO(simonjam): Why is Close() sometimes called twice?
594 break;
595
596 default:
597 CHECK(false);
598 break;
599 }
600 }
601
602 int HttpPipelinedConnectionImpl::ReadResponseBody(
603 int pipeline_id, IOBuffer* buf, int buf_len,
604 const CompletionCallback& callback) {
605 CHECK(ContainsKey(stream_info_map_, pipeline_id));
606 CHECK_EQ(active_read_id_, pipeline_id);
607 CHECK(stream_info_map_[pipeline_id].parser.get());
608 return stream_info_map_[pipeline_id].parser->ReadResponseBody(
609 buf, buf_len, callback);
610 }
611
612 UploadProgress HttpPipelinedConnectionImpl::GetUploadProgress(
613 int pipeline_id) const {
614 CHECK(ContainsKey(stream_info_map_, pipeline_id));
615 CHECK(stream_info_map_.find(pipeline_id)->second.parser.get());
616 return stream_info_map_.find(pipeline_id)->second.parser->GetUploadProgress();
617 }
618
619 HttpResponseInfo* HttpPipelinedConnectionImpl::GetResponseInfo(
620 int pipeline_id) {
621 CHECK(ContainsKey(stream_info_map_, pipeline_id));
622 CHECK(stream_info_map_.find(pipeline_id)->second.parser.get());
623 return stream_info_map_.find(pipeline_id)->second.parser->GetResponseInfo();
624 }
625
626 bool HttpPipelinedConnectionImpl::IsResponseBodyComplete(
627 int pipeline_id) const {
628 CHECK(ContainsKey(stream_info_map_, pipeline_id));
629 CHECK(stream_info_map_.find(pipeline_id)->second.parser.get());
630 return stream_info_map_.find(pipeline_id)->second.parser->
631 IsResponseBodyComplete();
632 }
633
634 bool HttpPipelinedConnectionImpl::CanFindEndOfResponse(int pipeline_id) const {
635 CHECK(ContainsKey(stream_info_map_, pipeline_id));
636 CHECK(stream_info_map_.find(pipeline_id)->second.parser.get());
637 return stream_info_map_.find(pipeline_id)->second.parser->
638 CanFindEndOfResponse();
639 }
640
641 bool HttpPipelinedConnectionImpl::IsConnectionReused(int pipeline_id) const {
642 CHECK(ContainsKey(stream_info_map_, pipeline_id));
643 if (pipeline_id > 1) {
644 return true;
645 }
646 ClientSocketHandle::SocketReuseType reuse_type = connection_->reuse_type();
647 return connection_->is_reused() ||
648 reuse_type == ClientSocketHandle::UNUSED_IDLE;
649 }
650
651 void HttpPipelinedConnectionImpl::SetConnectionReused(int pipeline_id) {
652 CHECK(ContainsKey(stream_info_map_, pipeline_id));
653 connection_->set_reuse_type(ClientSocketHandle::REUSED_IDLE);
654 }
655
656 int64 HttpPipelinedConnectionImpl::GetTotalReceivedBytes(
657 int pipeline_id) const {
658 CHECK(ContainsKey(stream_info_map_, pipeline_id));
659 if (stream_info_map_.find(pipeline_id)->second.parser.get())
660 return stream_info_map_.find(pipeline_id)->second.parser->received_bytes();
661 return 0;
662 }
663
664 bool HttpPipelinedConnectionImpl::GetLoadTimingInfo(
665 int pipeline_id, LoadTimingInfo* load_timing_info) const {
666 return connection_->GetLoadTimingInfo(IsConnectionReused(pipeline_id),
667 load_timing_info);
668 }
669
670 void HttpPipelinedConnectionImpl::GetSSLInfo(int pipeline_id,
671 SSLInfo* ssl_info) {
672 CHECK(ContainsKey(stream_info_map_, pipeline_id));
673 CHECK(stream_info_map_[pipeline_id].parser.get());
674 stream_info_map_[pipeline_id].parser->GetSSLInfo(ssl_info);
675 }
676
677 void HttpPipelinedConnectionImpl::GetSSLCertRequestInfo(
678 int pipeline_id,
679 SSLCertRequestInfo* cert_request_info) {
680 CHECK(ContainsKey(stream_info_map_, pipeline_id));
681 CHECK(stream_info_map_[pipeline_id].parser.get());
682 stream_info_map_[pipeline_id].parser->GetSSLCertRequestInfo(
683 cert_request_info);
684 }
685
686 void HttpPipelinedConnectionImpl::Drain(HttpPipelinedStream* stream,
687 HttpNetworkSession* session) {
688 HttpResponseHeaders* headers = stream->GetResponseInfo()->headers.get();
689 if (!stream->CanFindEndOfResponse() || headers->IsChunkEncoded() ||
690 !usable_) {
691 // TODO(simonjam): Drain chunk-encoded responses if they're relatively
692 // common.
693 stream->Close(true);
694 delete stream;
695 return;
696 }
697 HttpResponseBodyDrainer* drainer = new HttpResponseBodyDrainer(stream);
698 drainer->StartWithSize(session, headers->GetContentLength());
699 // |drainer| will delete itself when done.
700 }
701
702 void HttpPipelinedConnectionImpl::CheckHeadersForPipelineCompatibility(
703 int pipeline_id,
704 int result) {
705 if (result < OK) {
706 switch (result) {
707 // TODO(simonjam): Ignoring specific errors like this may not work.
708 // Collect metrics to see if this code is useful.
709 case ERR_ABORTED:
710 case ERR_INTERNET_DISCONNECTED:
711 case ERR_NETWORK_CHANGED:
712 // These errors are no fault of the server.
713 break;
714
715 default:
716 ReportPipelineFeedback(pipeline_id, PIPELINE_SOCKET_ERROR);
717 break;
718 }
719 return;
720 }
721 HttpResponseInfo* info = GetResponseInfo(pipeline_id);
722 const HttpVersion required_version(1, 1);
723 if (info->headers->GetParsedHttpVersion() < required_version) {
724 ReportPipelineFeedback(pipeline_id, OLD_HTTP_VERSION);
725 return;
726 }
727 if (!info->headers->IsKeepAlive() || !CanFindEndOfResponse(pipeline_id)) {
728 usable_ = false;
729 ReportPipelineFeedback(pipeline_id, MUST_CLOSE_CONNECTION);
730 return;
731 }
732 if (info->headers->HasHeader(
733 HttpAuth::GetChallengeHeaderName(HttpAuth::AUTH_SERVER))) {
734 ReportPipelineFeedback(pipeline_id, AUTHENTICATION_REQUIRED);
735 return;
736 }
737 ReportPipelineFeedback(pipeline_id, OK);
738 }
739
740 void HttpPipelinedConnectionImpl::ReportPipelineFeedback(int pipeline_id,
741 Feedback feedback) {
742 std::string feedback_str;
743 switch (feedback) {
744 case OK:
745 feedback_str = "OK";
746 break;
747
748 case PIPELINE_SOCKET_ERROR:
749 feedback_str = "PIPELINE_SOCKET_ERROR";
750 break;
751
752 case OLD_HTTP_VERSION:
753 feedback_str = "OLD_HTTP_VERSION";
754 break;
755
756 case MUST_CLOSE_CONNECTION:
757 feedback_str = "MUST_CLOSE_CONNECTION";
758 break;
759
760 case AUTHENTICATION_REQUIRED:
761 feedback_str = "AUTHENTICATION_REQUIRED";
762 break;
763
764 default:
765 NOTREACHED();
766 feedback_str = "UNKNOWN";
767 break;
768 }
769 net_log_.AddEvent(
770 NetLog::TYPE_HTTP_PIPELINED_CONNECTION_RECEIVED_HEADERS,
771 base::Bind(&NetLogReceivedHeadersCallback,
772 stream_info_map_[pipeline_id].source, &feedback_str));
773 delegate_->OnPipelineFeedback(this, feedback);
774 }
775
776 void HttpPipelinedConnectionImpl::QueueUserCallback(
777 int pipeline_id, const CompletionCallback& callback, int rv,
778 const tracked_objects::Location& from_here) {
779 CHECK(stream_info_map_[pipeline_id].pending_user_callback.is_null());
780 stream_info_map_[pipeline_id].pending_user_callback = callback;
781 base::MessageLoop::current()->PostTask(
782 from_here,
783 base::Bind(&HttpPipelinedConnectionImpl::FireUserCallback,
784 weak_factory_.GetWeakPtr(), pipeline_id, rv));
785 }
786
787 void HttpPipelinedConnectionImpl::FireUserCallback(int pipeline_id,
788 int result) {
789 if (ContainsKey(stream_info_map_, pipeline_id)) {
790 CHECK(!stream_info_map_[pipeline_id].pending_user_callback.is_null());
791 CompletionCallback callback =
792 stream_info_map_[pipeline_id].pending_user_callback;
793 stream_info_map_[pipeline_id].pending_user_callback.Reset();
794 callback.Run(result);
795 }
796 }
797
798 int HttpPipelinedConnectionImpl::depth() const {
799 return stream_info_map_.size();
800 }
801
802 bool HttpPipelinedConnectionImpl::usable() const {
803 return usable_;
804 }
805
806 bool HttpPipelinedConnectionImpl::active() const {
807 return active_;
808 }
809
810 const SSLConfig& HttpPipelinedConnectionImpl::used_ssl_config() const {
811 return used_ssl_config_;
812 }
813
814 const ProxyInfo& HttpPipelinedConnectionImpl::used_proxy_info() const {
815 return used_proxy_info_;
816 }
817
818 const BoundNetLog& HttpPipelinedConnectionImpl::net_log() const {
819 return net_log_;
820 }
821
822 bool HttpPipelinedConnectionImpl::was_npn_negotiated() const {
823 return was_npn_negotiated_;
824 }
825
826 NextProto HttpPipelinedConnectionImpl::protocol_negotiated()
827 const {
828 return protocol_negotiated_;
829 }
830
831 HttpPipelinedConnectionImpl::PendingSendRequest::PendingSendRequest()
832 : pipeline_id(0),
833 response(NULL) {
834 }
835
836 HttpPipelinedConnectionImpl::PendingSendRequest::~PendingSendRequest() {
837 }
838
839 HttpPipelinedConnectionImpl::StreamInfo::StreamInfo()
840 : state(STREAM_CREATED) {
841 }
842
843 HttpPipelinedConnectionImpl::StreamInfo::~StreamInfo() {
844 }
845
846 } // namespace net
OLDNEW
« no previous file with comments | « net/http/http_pipelined_connection_impl.h ('k') | net/http/http_pipelined_connection_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698