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

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

Issue 7289006: Basic HTTP pipelining support (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Better Close() handling and tests Created 9 years, 3 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) 2011 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/message_loop.h"
8 #include "base/stl_util.h"
9 #include "net/base/io_buffer.h"
10 #include "net/http/http_pipelined_stream.h"
11 #include "net/http/http_request_info.h"
12 #include "net/http/http_stream_parser.h"
13 #include "net/socket/client_socket_handle.h"
14
15 namespace net {
16
17 HttpPipelinedConnectionImpl::HttpPipelinedConnectionImpl(
18 ClientSocketHandle* connection,
19 HttpPipelinedConnection::Delegate* delegate,
20 const SSLConfig& used_ssl_config,
21 const ProxyInfo& used_proxy_info,
22 const BoundNetLog& net_log,
23 bool was_npn_negotiated)
24 : delegate_(delegate),
25 connection_(connection),
26 used_ssl_config_(used_ssl_config),
27 used_proxy_info_(used_proxy_info),
28 net_log_(net_log),
29 was_npn_negotiated_(was_npn_negotiated),
30 read_buf_(new GrowableIOBuffer()),
31 next_pipeline_id_(1),
32 active_(false),
33 usable_(true),
34 completed_one_request_(false),
35 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
36 send_next_state_(SEND_STATE_NONE),
37 ALLOW_THIS_IN_INITIALIZER_LIST(send_io_callback_(
38 this, &HttpPipelinedConnectionImpl::OnSendIOCallback)),
39 send_user_callback_(NULL),
40 read_next_state_(READ_STATE_NONE),
41 ALLOW_THIS_IN_INITIALIZER_LIST(read_io_callback_(
42 this, &HttpPipelinedConnectionImpl::OnReadIOCallback)),
43 read_user_callback_(NULL) {
44 DCHECK(connection_.get());
45 }
46
47 HttpPipelinedConnectionImpl::~HttpPipelinedConnectionImpl() {
48 DCHECK(depth() == 0);
49 DCHECK(parser_map_.empty());
50 DCHECK(callback_map_.empty());
51 DCHECK(deferred_request_queue_.empty());
52 DCHECK(request_order_.empty());
53 DCHECK_EQ(send_next_state_, SEND_STATE_NONE);
54 DCHECK_EQ(read_next_state_, READ_STATE_NONE);
55 DCHECK(!send_user_callback_);
56 DCHECK(!read_user_callback_);
57 if (!usable_) {
58 connection_->socket()->Disconnect();
59 }
60 connection_->Reset();
61 }
62
63 HttpStream* HttpPipelinedConnectionImpl::CreateNewStream() {
64 int pipeline_id = next_pipeline_id_++;
65 DCHECK(pipeline_id);
66 HttpPipelinedStream* stream = new HttpPipelinedStream(this, pipeline_id);
67 stream_state_map_.insert(std::make_pair(pipeline_id, STREAM_CREATED));
68 return stream;
69 }
70
71 void HttpPipelinedConnectionImpl::InitializeParser(
72 int pipeline_id,
73 const HttpRequestInfo* request,
74 const BoundNetLog& net_log) {
75 DCHECK(ContainsKey(stream_state_map_, pipeline_id));
76 DCHECK(!ContainsKey(parser_map_, pipeline_id));
77 stream_state_map_[pipeline_id] = STREAM_BOUND;
78 HttpStreamParser* parser = new HttpStreamParser(connection_.get(),
79 request,
80 read_buf_.get(),
81 net_log);
82 parser_map_.insert(std::make_pair(pipeline_id, parser));
83 if (!active_) {
84 active_ = true;
85 MessageLoop::current()->PostTask(
86 FROM_HERE,
87 method_factory_.NewRunnableMethod(
88 &HttpPipelinedConnectionImpl::FillPipeline));
89 }
90 }
91
92 void HttpPipelinedConnectionImpl::FillPipeline() {
93 delegate_->OnPipelineHasCapacity(this);
94 }
95
96 void HttpPipelinedConnectionImpl::OnStreamDeleted(int pipeline_id) {
97 DCHECK(ContainsKey(stream_state_map_, pipeline_id));
98
99 // TODO(simonjam): During proxy authentication, a stream might be deleted
100 // without Close() being called. Revisit this block when proxy support is
101 // added.
mmenke 2011/09/01 21:15:39 Seems to me this class is no longer implementing t
James Simonsen 2011/09/07 21:20:10 Done.
102 if (stream_state_map_[pipeline_id] != STREAM_CREATED &&
103 stream_state_map_[pipeline_id] != STREAM_UNUSED) {
104 DCHECK_EQ(stream_state_map_[pipeline_id], STREAM_CLOSED);
105 DCHECK(ContainsKey(parser_map_, pipeline_id));
106 DCHECK(!ContainsKey(callback_map_, pipeline_id));
mmenke 2011/09/01 21:15:39 nit: Could move this to the top of the function,
James Simonsen 2011/09/07 21:20:10 Done.
107
108 ParserMap::iterator it = parser_map_.find(pipeline_id);
109 delete it->second;
110 parser_map_.erase(it);
111 }
mmenke 2011/09/01 21:15:39 nit: Maybe add out of general paranoia: DCHECK(!
James Simonsen 2011/09/07 21:20:10 Done.
112 stream_state_map_.erase(pipeline_id);
113
114 MessageLoop::current()->PostTask(
115 FROM_HERE,
116 method_factory_.NewRunnableMethod(
117 &HttpPipelinedConnectionImpl::FillPipeline));
118 }
119
120 int HttpPipelinedConnectionImpl::SendRequest(int pipeline_id,
121 const std::string& request_line,
122 const HttpRequestHeaders& headers,
123 UploadDataStream* request_body,
124 HttpResponseInfo* response,
125 CompletionCallback* callback) {
126 DCHECK(ContainsKey(stream_state_map_, pipeline_id));
127 DCHECK_EQ(stream_state_map_[pipeline_id], STREAM_BOUND);
128 if (!usable_) {
129 return ERR_PIPELINE_EVICTION;
130 }
131
132 DeferredSendRequest deferred_request;
133 deferred_request.pipeline_id = pipeline_id;
134 deferred_request.request_line = request_line;
135 deferred_request.headers = headers;
136 deferred_request.request_body = request_body;
137 deferred_request.response = response;
138 deferred_request.callback = callback;
139 deferred_request_queue_.push(deferred_request);
140
141 if (send_next_state_ == SEND_STATE_NONE) {
142 send_next_state_ = SEND_STATE_NEXT_REQUEST;
143 return DoSendRequestLoop(OK);
144 } else {
145 return ERR_IO_PENDING;
146 }
147 }
148
149 int HttpPipelinedConnectionImpl::DoSendRequestLoop(int result) {
150 int rv = result;
151 do {
152 SendRequestState state = send_next_state_;
153 send_next_state_ = SEND_STATE_NONE;
154 switch (state) {
155 case SEND_STATE_NEXT_REQUEST:
156 rv = DoSendNextRequest(rv);
157 break;
158 case SEND_STATE_COMPLETE:
159 rv = DoSendComplete(rv);
160 break;
161 case SEND_STATE_UNUSABLE:
162 rv = DoEvictPendingSendRequests(rv);
163 break;
164 default:
165 NOTREACHED() << "bad send state: " << state;
166 rv = ERR_FAILED;
167 break;
168 }
169 } while (rv != ERR_IO_PENDING && send_next_state_ != SEND_STATE_NONE);
170 return rv;
171 }
172
173 void HttpPipelinedConnectionImpl::OnSendIOCallback(int result) {
174 DCHECK(send_user_callback_);
175 DoSendRequestLoop(result);
176 }
177
178 int HttpPipelinedConnectionImpl::DoSendNextRequest(int result) {
179 DCHECK(!deferred_request_queue_.empty());
180 const DeferredSendRequest& deferred_request = deferred_request_queue_.front();
181 DCHECK(ContainsKey(stream_state_map_, deferred_request.pipeline_id));
182 if (stream_state_map_[deferred_request.pipeline_id] == STREAM_CLOSED) {
183 deferred_request_queue_.pop();
184 if (deferred_request_queue_.empty()) {
185 send_next_state_ = SEND_STATE_NONE;
186 } else {
187 send_next_state_ = SEND_STATE_NEXT_REQUEST;
188 }
189 return OK;
190 }
191 DCHECK(ContainsKey(parser_map_, deferred_request.pipeline_id));
192 int rv = parser_map_[deferred_request.pipeline_id]->SendRequest(
193 deferred_request.request_line,
194 deferred_request.headers,
195 deferred_request.request_body,
196 deferred_request.response,
197 &send_io_callback_);
198 // |result| == ERR_IO_PENDING means this function was *not* called on the same
199 // stack as SendRequest(). That means we returned ERR_IO_PENDING to
200 // SendRequest() earlier and now need to invoke its callback.
mmenke 2011/09/01 21:15:39 nit: "now need" -> "will need". "Now need" has
James Simonsen 2011/09/07 21:20:10 Done.
201 if (result == ERR_IO_PENDING || rv == ERR_IO_PENDING) {
202 send_user_callback_ = deferred_request.callback;
203 }
204 stream_state_map_[deferred_request.pipeline_id] = STREAM_SENDING;
205 send_next_state_ = SEND_STATE_COMPLETE;
206 return rv;
207 }
208
209 int HttpPipelinedConnectionImpl::DoSendComplete(int result) {
210 DCHECK(!deferred_request_queue_.empty());
211 const DeferredSendRequest& deferred_request = deferred_request_queue_.front();
212 DCHECK_EQ(stream_state_map_[deferred_request.pipeline_id], STREAM_SENDING);
213 request_order_.push(deferred_request.pipeline_id);
214 stream_state_map_[deferred_request.pipeline_id] = STREAM_SENT;
215 deferred_request_queue_.pop();
216 if (send_user_callback_) {
217 CompletionCallback* callback = send_user_callback_;
218 send_user_callback_ = NULL;
219 callback->Run(result);
mmenke 2011/09/01 21:15:39 Looks to me like this will always result in cancel
James Simonsen 2011/09/07 21:20:10 Done.
220 }
221 if (result < OK) {
222 send_next_state_ = SEND_STATE_UNUSABLE;
223 usable_ = false;
224 if (result == ERR_SOCKET_NOT_CONNECTED && completed_one_request_)
225 return ERR_PIPELINE_EVICTION;
226 else
227 return result;
228 }
229 if (deferred_request_queue_.empty()) {
230 send_next_state_ = SEND_STATE_NONE;
231 return OK;
232 } else {
mmenke 2011/09/01 21:15:39 nit: Else not needed, because of the above return
James Simonsen 2011/09/07 21:20:10 Done.
233 send_next_state_ = SEND_STATE_NEXT_REQUEST;
234 MessageLoop::current()->PostTask(
235 FROM_HERE,
236 method_factory_.NewRunnableMethod(
237 &HttpPipelinedConnectionImpl::DoSendRequestLoop,
238 ERR_IO_PENDING));
239 return ERR_IO_PENDING; // Wait for the task to fire.
240 }
241 }
242
243 int HttpPipelinedConnectionImpl::DoEvictPendingSendRequests(int result) {
244 send_next_state_ = SEND_STATE_NONE;
245 while (!deferred_request_queue_.empty()) {
246 const DeferredSendRequest& evicted_send = deferred_request_queue_.front();
247 if (stream_state_map_[evicted_send.pipeline_id] != STREAM_CLOSED) {
248 evicted_send.callback->Run(ERR_PIPELINE_EVICTION);
249 }
250 deferred_request_queue_.pop();
251 }
252 return result;
253 }
254
255 int HttpPipelinedConnectionImpl::ReadResponseHeaders(
256 int pipeline_id,
257 CompletionCallback* callback) {
258 DCHECK(ContainsKey(stream_state_map_, pipeline_id));
259 DCHECK_EQ(stream_state_map_[pipeline_id], STREAM_SENT);
260 DCHECK(!ContainsKey(callback_map_, pipeline_id));
261 if (!usable_) {
262 return ERR_PIPELINE_EVICTION;
263 }
264 stream_state_map_[pipeline_id] = STREAM_READ_PENDING;
265 callback_map_[pipeline_id] = callback;
266 if (read_next_state_ == READ_STATE_NONE) {
267 read_next_state_ = READ_STATE_NEXT_HEADERS;
268 return DoReadHeadersLoop(OK);
269 } else {
270 return ERR_IO_PENDING;
271 }
272 }
273
274 int HttpPipelinedConnectionImpl::DoReadHeadersLoop(int result) {
275 int rv = result;
276 do {
277 ReadHeadersState state = read_next_state_;
278 read_next_state_ = READ_STATE_NONE;
279 switch (state) {
280 case READ_STATE_NEXT_HEADERS:
281 rv = DoReadNextHeaders(rv);
282 break;
283 case READ_STATE_COMPLETE:
284 rv = DoReadHeadersComplete(rv);
285 break;
286 case READ_STATE_WAITING_FOR_CLOSE:
287 rv = DoReadWaitingForClose(rv);
288 return rv;
289 case READ_STATE_STREAM_CLOSED:
290 rv = DoReadStreamClosed();
291 break;
292 case READ_STATE_UNUSABLE:
293 rv = DoEvictPendingReadHeaders(rv);
294 break;
295 case READ_STATE_NONE:
296 break;
297 default:
298 NOTREACHED() << "bad read state";
299 rv = ERR_FAILED;
300 break;
301 }
302 } while (rv != ERR_IO_PENDING && read_next_state_ != READ_STATE_NONE);
303 return rv;
304 }
305
306 void HttpPipelinedConnectionImpl::OnReadIOCallback(int result) {
307 DCHECK(read_user_callback_ != NULL);
308 DoReadHeadersLoop(result);
309 }
310
311 int HttpPipelinedConnectionImpl::DoReadNextHeaders(int result) {
312 DCHECK(!request_order_.empty());
313 int pipeline_id = request_order_.front();
314 DCHECK(ContainsKey(stream_state_map_, pipeline_id));
315 if (stream_state_map_[pipeline_id] == STREAM_CLOSED) {
316 // Since nobody will read whatever data is on the pipeline associated with
317 // this closed request, we must shut down the rest of the pipeline.
318 read_next_state_ = READ_STATE_UNUSABLE;
319 return OK;
320 }
321 CallbackMap::iterator it = callback_map_.find(pipeline_id);
322 if (it == callback_map_.end()) {
323 return ERR_IO_PENDING;
324 }
325 DCHECK(ContainsKey(parser_map_, pipeline_id));
326
327 if (result == ERR_IO_PENDING) {
328 DCHECK_EQ(stream_state_map_[pipeline_id], STREAM_ACTIVE);
329 } else {
330 DCHECK_EQ(stream_state_map_[pipeline_id], STREAM_READ_PENDING);
331 stream_state_map_[pipeline_id] = STREAM_ACTIVE;
332 }
333
334 int rv = parser_map_[pipeline_id]->ReadResponseHeaders(&read_io_callback_);
335 if (rv == ERR_IO_PENDING) {
336 read_next_state_ = READ_STATE_COMPLETE;
337 read_user_callback_ = it->second;
338 } else if (rv < OK) {
339 read_next_state_ = READ_STATE_WAITING_FOR_CLOSE;
340 if (rv == ERR_SOCKET_NOT_CONNECTED && completed_one_request_)
341 rv = ERR_PIPELINE_EVICTION;
342 } else {
343 DCHECK_LE(OK, rv);
344 read_next_state_ = READ_STATE_WAITING_FOR_CLOSE;
345 }
346
347 // |result| == ERR_IO_PENDING means this function was *not* called on the same
348 // stack as ReadResponseHeaders(). That means we returned ERR_IO_PENDING to
349 // ReadResponseHeaders() earlier and now need to invoke its callback.
350 if (rv != ERR_IO_PENDING && result == ERR_IO_PENDING) {
351 read_next_state_ = READ_STATE_WAITING_FOR_CLOSE;
352 read_user_callback_ = it->second;
353 MessageLoop::current()->PostTask(
354 FROM_HERE,
355 method_factory_.NewRunnableMethod(
356 &HttpPipelinedConnectionImpl::FireReadUserCallback,
357 rv));
358 }
359 return rv;
360 }
361
362 int HttpPipelinedConnectionImpl::DoReadHeadersComplete(int result) {
363 read_next_state_ = READ_STATE_WAITING_FOR_CLOSE;
364 if (read_user_callback_) {
365 MessageLoop::current()->PostTask(
366 FROM_HERE,
367 method_factory_.NewRunnableMethod(
368 &HttpPipelinedConnectionImpl::FireReadUserCallback,
369 result));
370 }
371 return result;
372 }
373
374 int HttpPipelinedConnectionImpl::DoReadWaitingForClose(int result) {
375 read_next_state_ = READ_STATE_WAITING_FOR_CLOSE;
376 return result;
377 }
378
379 int HttpPipelinedConnectionImpl::DoReadStreamClosed() {
380 DCHECK(!request_order_.empty());
381 int pipeline_id = request_order_.front();
382 DCHECK(ContainsKey(callback_map_, pipeline_id));
383 DCHECK_EQ(stream_state_map_[pipeline_id], STREAM_CLOSED);
384 callback_map_.erase(pipeline_id);
385 request_order_.pop();
386 if (!usable_) {
387 read_next_state_ = READ_STATE_UNUSABLE;
388 return OK;
389 } else {
390 completed_one_request_ = true;
391 if (request_order_.empty() ||
392 !ContainsKey(callback_map_, request_order_.front())) {
393 read_next_state_ = READ_STATE_NONE;
394 return OK;
395 } else {
396 stream_state_map_[request_order_.front()] = STREAM_ACTIVE;
397 read_next_state_ = READ_STATE_NEXT_HEADERS;
398 MessageLoop::current()->PostTask(
399 FROM_HERE,
400 method_factory_.NewRunnableMethod(
401 &HttpPipelinedConnectionImpl::DoReadHeadersLoop,
402 ERR_IO_PENDING));
403 return ERR_IO_PENDING; // Wait for the task to fire.
404 }
405 }
406 }
407
408 int HttpPipelinedConnectionImpl::DoEvictPendingReadHeaders(int result) {
409 while (!request_order_.empty()) {
410 int evicted_id = request_order_.front();
411 request_order_.pop();
412 CallbackMap::iterator cb_it = callback_map_.find(evicted_id);
413 if (cb_it == callback_map_.end()) {
414 continue;
415 }
416 if (stream_state_map_[evicted_id] != STREAM_CLOSED) {
417 cb_it->second->Run(ERR_PIPELINE_EVICTION);
418 }
419 callback_map_.erase(cb_it);
420 }
421 DCHECK(callback_map_.empty());
422 read_next_state_ = READ_STATE_NONE;
423 return result;
424 }
425
426 void HttpPipelinedConnectionImpl::Close(int pipeline_id,
427 bool not_reusable) {
428 DCHECK(ContainsKey(stream_state_map_, pipeline_id));
429 switch (stream_state_map_[pipeline_id]) {
430 case STREAM_CREATED:
431 stream_state_map_[pipeline_id] = STREAM_UNUSED;
432 break;
433
434 case STREAM_BOUND:
435 stream_state_map_[pipeline_id] = STREAM_CLOSED;
436 break;
437
438 case STREAM_SENDING:
439 usable_ = false;
440 stream_state_map_[pipeline_id] = STREAM_CLOSED;
441 send_user_callback_ = NULL;
442 send_next_state_ = SEND_STATE_UNUSABLE;
443 DoSendRequestLoop(OK);
444 break;
445
446 case STREAM_SENT:
447 case STREAM_READ_PENDING:
448 usable_ = false;
449 stream_state_map_[pipeline_id] = STREAM_CLOSED;
450 if (read_next_state_ == READ_STATE_NONE) {
451 read_next_state_ = READ_STATE_UNUSABLE;
452 DoReadHeadersLoop(OK);
453 }
454 break;
455
456 case STREAM_ACTIVE:
457 stream_state_map_[pipeline_id] = STREAM_CLOSED;
458 if (not_reusable) {
459 usable_ = false;
460 }
461 read_next_state_ = READ_STATE_STREAM_CLOSED;
462 read_user_callback_ = NULL;
463 DoReadHeadersLoop(OK);
464 break;
465
466 case STREAM_CLOSED:
467 case STREAM_UNUSED:
468 // TODO(simonjam): Why is Close() sometimes called twice?
469 break;
470
471 default:
472 NOTREACHED();
473 break;
474 }
475 }
476
477 int HttpPipelinedConnectionImpl::ReadResponseBody(
478 int pipeline_id,
479 IOBuffer* buf,
480 int buf_len,
481 CompletionCallback* callback) {
482 DCHECK(ContainsKey(stream_state_map_, pipeline_id));
483 DCHECK(!request_order_.empty());
484 DCHECK(pipeline_id == request_order_.front());
485 DCHECK(ContainsKey(parser_map_, pipeline_id));
486 return parser_map_[pipeline_id]->ReadResponseBody(buf, buf_len, callback);
487 }
488
489 uint64 HttpPipelinedConnectionImpl::GetUploadProgress(int pipeline_id) const {
490 DCHECK(ContainsKey(stream_state_map_, pipeline_id));
491 DCHECK(ContainsKey(parser_map_, pipeline_id));
492 return parser_map_.find(pipeline_id)->second->GetUploadProgress();
493 }
494
495 HttpResponseInfo* HttpPipelinedConnectionImpl::GetResponseInfo(
496 int pipeline_id) {
497 DCHECK(ContainsKey(stream_state_map_, pipeline_id));
498 DCHECK(ContainsKey(parser_map_, pipeline_id));
499 return parser_map_[pipeline_id]->GetResponseInfo();
500 }
501
502 bool HttpPipelinedConnectionImpl::IsResponseBodyComplete(
503 int pipeline_id) const {
504 DCHECK(ContainsKey(stream_state_map_, pipeline_id));
505 DCHECK(ContainsKey(parser_map_, pipeline_id));
506 return parser_map_.find(pipeline_id)->second->IsResponseBodyComplete();
507 }
508
509 bool HttpPipelinedConnectionImpl::CanFindEndOfResponse(int pipeline_id) const {
510 DCHECK(ContainsKey(stream_state_map_, pipeline_id));
511 DCHECK(ContainsKey(parser_map_, pipeline_id));
512 return parser_map_.find(pipeline_id)->second->CanFindEndOfResponse();
mmenke 2011/09/01 21:15:39 Half the time you use "parser_map_.find(pipeline_i
James Simonsen 2011/09/07 21:20:10 I prefer [] too, but it isn't const. So I used it
513 }
514
515 bool HttpPipelinedConnectionImpl::IsMoreDataBuffered(int pipeline_id) const {
516 DCHECK(ContainsKey(stream_state_map_, pipeline_id));
517 return read_buf_->offset();
518 }
519
520 bool HttpPipelinedConnectionImpl::IsConnectionReused(int pipeline_id) const {
521 DCHECK(ContainsKey(stream_state_map_, pipeline_id));
522 if (pipeline_id > 1) {
523 return true;
524 }
525 ClientSocketHandle::SocketReuseType reuse_type = connection_->reuse_type();
526 return connection_->is_reused() ||
527 reuse_type == ClientSocketHandle::UNUSED_IDLE;
528 }
529
530 void HttpPipelinedConnectionImpl::SetConnectionReused(int pipeline_id) {
531 DCHECK(ContainsKey(stream_state_map_, pipeline_id));
532 connection_->set_is_reused(true);
533 }
534
535 void HttpPipelinedConnectionImpl::GetSSLInfo(int pipeline_id,
536 SSLInfo* ssl_info) {
537 DCHECK(ContainsKey(stream_state_map_, pipeline_id));
538 DCHECK(ContainsKey(parser_map_, pipeline_id));
539 return parser_map_[pipeline_id]->GetSSLInfo(ssl_info);
540 }
541
542 void HttpPipelinedConnectionImpl::GetSSLCertRequestInfo(
543 int pipeline_id,
544 SSLCertRequestInfo* cert_request_info) {
545 DCHECK(ContainsKey(stream_state_map_, pipeline_id));
546 DCHECK(ContainsKey(parser_map_, pipeline_id));
547 return parser_map_[pipeline_id]->GetSSLCertRequestInfo(cert_request_info);
548 }
549
550 void HttpPipelinedConnectionImpl::FireReadUserCallback(
551 int result) {
552 if (read_user_callback_) {
553 read_user_callback_->Run(result);
554 read_user_callback_ = NULL;
555 }
556 }
557
558 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698