spdy_http_stream.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/spdy/spdy_http_stream.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <algorithm>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <list>
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string>
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/load_flags.h"
143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/base/net_util.h"
15513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "net/http/http_request_headers.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/http/http_request_info.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/http/http_response_info.h"
183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/http/http_util.h"
193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/spdy/spdy_http_utils.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/spdy/spdy_session.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace net {
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenSpdyHttpStream::SpdyHttpStream(SpdySession* spdy_session,
2521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                               bool direct)
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : ALLOW_THIS_IN_INITIALIZER_LIST(read_callback_factory_(this)),
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      stream_(NULL),
283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      spdy_session_(spdy_session),
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      response_info_(NULL),
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      download_finished_(false),
31201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      response_headers_received_(false),
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      user_callback_(NULL),
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      user_buffer_len_(0),
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      buffered_read_callback_pending_(false),
353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      more_read_data_pending_(false),
363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      direct_(direct) { }
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid SpdyHttpStream::InitializeWithExistingStream(SpdyStream* spdy_stream) {
3921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  stream_ = spdy_stream;
4021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  stream_->SetDelegate(this);
4121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  response_headers_received_ = true;
4221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
4321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSpdyHttpStream::~SpdyHttpStream() {
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (stream_)
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    stream_->DetachDelegate();
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint SpdyHttpStream::InitializeStream(const HttpRequestInfo* request_info,
503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                     const BoundNetLog& stream_net_log,
513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                     CompletionCallback* callback) {
5221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(!stream_.get());
533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (spdy_session_->IsClosed())
543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   return ERR_CONNECTION_CLOSED;
553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request_info_ = request_info;
573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (request_info_->method == "GET") {
583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    int error = spdy_session_->GetPushStream(request_info_->url, &stream_,
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             stream_net_log);
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (error != OK)
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return error;
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (stream_.get())
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return OK;
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return spdy_session_->CreateStream(request_info_->url,
683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                     request_info_->priority, &stream_,
693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                     stream_net_log, callback);
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst HttpResponseInfo* SpdyHttpStream::GetResponseInfo() const {
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return response_info_;
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochuint64 SpdyHttpStream::GetUploadProgress() const {
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!request_body_stream_.get())
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return 0;
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return request_body_stream_->position();
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint SpdyHttpStream::ReadResponseHeaders(CompletionCallback* callback) {
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(callback);
853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CHECK(!stream_->cancelled());
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (stream_->closed())
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return stream_->response_status();
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Check if we already have the response headers. If so, return synchronously.
913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if(stream_->response_received()) {
923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    CHECK(stream_->is_idle());
933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return OK;
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Still waiting for the response, return IO_PENDING.
973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CHECK(!user_callback_);
983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  user_callback_ = callback;
993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return ERR_IO_PENDING;
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint SpdyHttpStream::ReadResponseBody(
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    IOBuffer* buf, int buf_len, CompletionCallback* callback) {
1043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CHECK(stream_->is_idle());
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(buf);
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(buf_len);
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(callback);
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If we have data buffered, complete the IO immediately.
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!response_body_.empty()) {
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int bytes_read = 0;
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    while (!response_body_.empty() && buf_len > 0) {
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      scoped_refptr<IOBufferWithSize> data = response_body_.front();
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      const int bytes_to_copy = std::min(buf_len, data->size());
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      memcpy(&(buf->data()[bytes_read]), data->data(), bytes_to_copy);
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      buf_len -= bytes_to_copy;
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (bytes_to_copy == data->size()) {
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        response_body_.pop_front();
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        const int bytes_remaining = data->size() - bytes_to_copy;
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        IOBufferWithSize* new_buffer = new IOBufferWithSize(bytes_remaining);
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        memcpy(new_buffer->data(), &(data->data()[bytes_to_copy]),
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               bytes_remaining);
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        response_body_.pop_front();
125513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        response_body_.push_front(make_scoped_refptr(new_buffer));
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      bytes_read += bytes_to_copy;
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
12921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (SpdySession::flow_control())
1303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      stream_->IncreaseRecvWindowSize(bytes_read);
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return bytes_read;
1323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else if (stream_->closed()) {
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return stream_->response_status();
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(!user_callback_);
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(!user_buffer_);
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK_EQ(0, user_buffer_len_);
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  user_callback_ = callback;
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  user_buffer_ = buf;
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  user_buffer_len_ = buf_len;
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return ERR_IO_PENDING;
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid SpdyHttpStream::Close(bool not_reusable) {
1473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Note: the not_reusable flag has no meaning for SPDY streams.
1483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  Cancel();
1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
15221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenHttpStream* SpdyHttpStream::RenewStreamForAuth() {
15321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return NULL;
15421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
15521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
15621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool SpdyHttpStream::IsResponseBodyComplete() const {
15721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!stream_)
15821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return false;
15921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return stream_->closed();
16021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
16121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
16221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool SpdyHttpStream::CanFindEndOfResponse() const {
16321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return true;
16421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
16521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
16621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool SpdyHttpStream::IsMoreDataBuffered() const {
16721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return false;
16821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
16921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
17021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool SpdyHttpStream::IsConnectionReused() const {
17121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return spdy_session_->IsReused();
17221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
17321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
17421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid SpdyHttpStream::SetConnectionReused() {
17521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // SPDY doesn't need an indicator here.
17621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
17721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
178513209b27ff55e2841eac0e4120199c23acce758Ben Murdochint SpdyHttpStream::SendRequest(const HttpRequestHeaders& request_headers,
1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                UploadDataStream* request_body,
1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                HttpResponseInfo* response,
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                CompletionCallback* callback) {
1823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  base::Time request_time = base::Time::Now();
1833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CHECK(stream_.get());
1843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  stream_->SetDelegate(this);
1863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  linked_ptr<spdy::SpdyHeaderBlock> headers(new spdy::SpdyHeaderBlock);
188731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers,
189731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                   headers.get(), direct_);
1903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  stream_->set_spdy_headers(headers);
1913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  stream_->SetRequestTime(request_time);
1933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // This should only get called in the case of a request occurring
1943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // during server push that has already begun but hasn't finished,
1953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // so we set the response's request time to be the actual one
1963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (response_info_)
1973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    response_info_->request_time = request_time;
1983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CHECK(!request_body_stream_.get());
2003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (request_body) {
2013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (request_body->size())
2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      request_body_stream_.reset(request_body);
2033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    else
2043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      delete request_body;
2053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(callback);
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(!stream_->cancelled());
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(response);
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!stream_->pushed() && stream_->closed()) {
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (stream_->response_status() == OK)
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return ERR_FAILED;
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return stream_->response_status();
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // SendRequest can be called in two cases.
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // a) A client initiated request. In this case, |response_info_| should be
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //    NULL to start with.
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // b) A client request which matches a response that the server has already
2233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  //    pushed.
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (push_response_info_.get()) {
2253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    *response = *(push_response_info_.get());
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    push_response_info_.reset();
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
2283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  else
2293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DCHECK_EQ(static_cast<HttpResponseInfo*>(NULL), response_info_);
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response_info_ = response;
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool has_upload_data = request_body_stream_.get() != NULL;
2343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int result = stream_->SendRequest(has_upload_data);
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result == ERR_IO_PENDING) {
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CHECK(!user_callback_);
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    user_callback_ = callback;
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SpdyHttpStream::Cancel() {
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (spdy_session_)
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    spdy_session_->CancelPendingCreateStreams(&stream_);
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  user_callback_ = NULL;
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (stream_)
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    stream_->Cancel();
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SpdyHttpStream::OnSendHeadersComplete(int status) {
2513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (user_callback_)
2523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DoCallback(status);
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return request_body_stream_.get() == NULL;
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint SpdyHttpStream::OnSendBody() {
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(request_body_stream_.get());
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int buf_len = static_cast<int>(request_body_stream_->buf_len());
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!buf_len)
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return OK;
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return stream_->WriteStreamData(request_body_stream_->buf(), buf_len,
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  spdy::DATA_FLAG_FIN);
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SpdyHttpStream::OnSendBodyComplete(int status) {
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(request_body_stream_.get());
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request_body_stream_->DidConsume(status);
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return request_body_stream_->eof();
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint SpdyHttpStream::OnResponseReceived(const spdy::SpdyHeaderBlock& response,
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       base::Time response_time,
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       int status) {
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!response_info_) {
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(stream_->pushed());
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    push_response_info_.reset(new HttpResponseInfo);
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    response_info_ = push_response_info_.get();
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
280201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // If the response is already received, these headers are too late.
281201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (response_headers_received_) {
282201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    LOG(WARNING) << "SpdyHttpStream headers received after response started.";
283201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return OK;
284201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
285201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
2863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // TODO(mbelshe): This is the time of all headers received, not just time
2873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // to first byte.
2883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  response_info_->response_time = base::Time::Now();
2893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!SpdyHeadersToHttpResponse(response, response_info_)) {
291201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // We might not have complete headers yet.
292201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return ERR_INCOMPLETE_SPDY_HEADERS;
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
295201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  response_headers_received_ = true;
29621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Don't store the SSLInfo in the response here, HttpNetworkTransaction
29721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // will take care of that part.
29821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  SSLInfo ssl_info;
29921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  stream_->GetSSLInfo(&ssl_info,
300201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                      &response_info_->was_npn_negotiated);
301201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  response_info_->request_time = stream_->GetRequestTime();
302201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  response_info_->vary_data.Init(*request_info_, *response_info_->headers);
303201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // TODO(ahendrickson): This is recorded after the entire SYN_STREAM control
304201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // frame has been received and processed.  Move to framer?
305201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  response_info_->response_time = response_time;
306201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (user_callback_)
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DoCallback(status);
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return status;
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SpdyHttpStream::OnDataReceived(const char* data, int length) {
313201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // SpdyStream won't call us with data if the header block didn't contain a
314201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // valid set of headers.  So we don't expect to not have headers received
315201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // here.
316201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK(response_headers_received_);
317201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Note that data may be received for a SpdyStream prior to the user calling
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // ReadResponseBody(), therefore user_buffer_ may be NULL.  This may often
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // happen for server initiated streams.
3213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(!stream_->closed() || stream_->pushed());
3223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (length > 0) {
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Save the received data.
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    IOBufferWithSize* io_buffer = new IOBufferWithSize(length);
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    memcpy(io_buffer->data(), data, length);
326513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    response_body_.push_back(make_scoped_refptr(io_buffer));
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (user_buffer_) {
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Handing small chunks of data to the caller creates measurable overhead.
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We buffer data in short time-spans and send a single read notification.
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ScheduleBufferedReadCallback();
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SpdyHttpStream::OnDataSent(int length) {
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // For HTTP streams, no data is sent from the client while in the OPEN state,
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // so it is never called.
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NOTREACHED();
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SpdyHttpStream::OnClose(int status) {
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool invoked_callback = false;
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (status == net::OK) {
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We need to complete any pending buffered read now.
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    invoked_callback = DoBufferedReadCallback();
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!invoked_callback && user_callback_)
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DoCallback(status);
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SpdyHttpStream::ScheduleBufferedReadCallback() {
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If there is already a scheduled DoBufferedReadCallback, don't issue
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // another one.  Mark that we have received more data and return.
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (buffered_read_callback_pending_) {
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    more_read_data_pending_ = true;
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  more_read_data_pending_ = false;
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  buffered_read_callback_pending_ = true;
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const int kBufferTimeMs = 1;
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MessageLoop::current()->PostDelayedTask(FROM_HERE, read_callback_factory_.
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(&SpdyHttpStream::DoBufferedReadCallback),
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kBufferTimeMs);
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Checks to see if we should wait for more buffered data before notifying
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the caller.  Returns true if we should wait, false otherwise.
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SpdyHttpStream::ShouldWaitForMoreBufferedData() const {
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the response is complete, there is no point in waiting.
3723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (stream_->closed())
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int bytes_buffered = 0;
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::list<scoped_refptr<IOBufferWithSize> >::const_iterator it;
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (it = response_body_.begin();
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       it != response_body_.end() && bytes_buffered < user_buffer_len_;
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       ++it)
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bytes_buffered += (*it)->size();
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return bytes_buffered < user_buffer_len_;
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SpdyHttpStream::DoBufferedReadCallback() {
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  read_callback_factory_.RevokeAll();
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  buffered_read_callback_pending_ = false;
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the transaction is cancelled or errored out, we don't need to complete
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the read.
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!stream_ || stream_->response_status() != OK || stream_->cancelled())
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // When more_read_data_pending_ is true, it means that more data has
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // arrived since we started waiting.  Wait a little longer and continue
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to buffer.
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (more_read_data_pending_ && ShouldWaitForMoreBufferedData()) {
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ScheduleBufferedReadCallback();
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int rv = 0;
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (user_buffer_) {
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rv = ReadResponseBody(user_buffer_, user_buffer_len_, user_callback_);
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CHECK_NE(rv, ERR_IO_PENDING);
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    user_buffer_ = NULL;
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    user_buffer_len_ = 0;
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DoCallback(rv);
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SpdyHttpStream::DoCallback(int rv) {
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK_NE(rv, ERR_IO_PENDING);
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(user_callback_);
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Since Run may result in being called back, clear user_callback_ in advance.
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CompletionCallback* c = user_callback_;
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  user_callback_ = NULL;
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  c->Run(rv);
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid SpdyHttpStream::GetSSLInfo(SSLInfo* ssl_info) {
4253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(stream_);
4263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bool using_npn;
4273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  stream_->GetSSLInfo(ssl_info, &using_npn);
4283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
4293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid SpdyHttpStream::GetSSLCertRequestInfo(
4313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    SSLCertRequestInfo* cert_request_info) {
4323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(stream_);
4333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  stream_->GetSSLCertRequestInfo(cert_request_info);
4343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
4353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace net
437