Speech refactoring: Reimplemented SpeechRecognitionManagerImpl as a FSM. (CL1.7)
[chromium-blink-merge.git] / net / spdy / spdy_http_stream.cc
blobcdda4f2f9a085f6d193d35c9f68cf5278896576d
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.
5 #include "net/spdy/spdy_http_stream.h"
7 #include <algorithm>
8 #include <list>
9 #include <string>
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/logging.h"
14 #include "base/message_loop.h"
15 #include "net/base/address_list.h"
16 #include "net/base/host_port_pair.h"
17 #include "net/base/load_flags.h"
18 #include "net/base/net_util.h"
19 #include "net/http/http_request_headers.h"
20 #include "net/http/http_request_info.h"
21 #include "net/http/http_response_info.h"
22 #include "net/http/http_util.h"
23 #include "net/spdy/spdy_http_utils.h"
24 #include "net/spdy/spdy_session.h"
26 namespace net {
28 SpdyHttpStream::SpdyHttpStream(SpdySession* spdy_session,
29 bool direct)
30 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
31 stream_(NULL),
32 spdy_session_(spdy_session),
33 response_info_(NULL),
34 download_finished_(false),
35 response_headers_received_(false),
36 user_buffer_len_(0),
37 buffered_read_callback_pending_(false),
38 more_read_data_pending_(false),
39 direct_(direct) { }
41 void SpdyHttpStream::InitializeWithExistingStream(SpdyStream* spdy_stream) {
42 stream_ = spdy_stream;
43 stream_->SetDelegate(this);
44 response_headers_received_ = true;
47 SpdyHttpStream::~SpdyHttpStream() {
48 if (stream_)
49 stream_->DetachDelegate();
52 int SpdyHttpStream::InitializeStream(const HttpRequestInfo* request_info,
53 const BoundNetLog& stream_net_log,
54 const CompletionCallback& callback) {
55 DCHECK(!stream_.get());
56 if (spdy_session_->IsClosed())
57 return ERR_CONNECTION_CLOSED;
59 request_info_ = request_info;
60 if (request_info_->method == "GET") {
61 int error = spdy_session_->GetPushStream(request_info_->url, &stream_,
62 stream_net_log);
63 if (error != OK)
64 return error;
67 if (stream_.get())
68 return OK;
70 return spdy_session_->CreateStream(request_info_->url,
71 request_info_->priority, &stream_,
72 stream_net_log, callback);
75 const HttpResponseInfo* SpdyHttpStream::GetResponseInfo() const {
76 return response_info_;
79 uint64 SpdyHttpStream::GetUploadProgress() const {
80 if (!request_body_stream_.get())
81 return 0;
83 return request_body_stream_->position();
86 int SpdyHttpStream::ReadResponseHeaders(const CompletionCallback& callback) {
87 CHECK(!callback.is_null());
88 CHECK(!stream_->cancelled());
90 if (stream_->closed())
91 return stream_->response_status();
93 // Check if we already have the response headers. If so, return synchronously.
94 if(stream_->response_received()) {
95 CHECK(stream_->is_idle());
96 return OK;
99 // Still waiting for the response, return IO_PENDING.
100 CHECK(callback_.is_null());
101 callback_ = callback;
102 return ERR_IO_PENDING;
105 int SpdyHttpStream::ReadResponseBody(
106 IOBuffer* buf, int buf_len, const CompletionCallback& callback) {
107 CHECK(stream_->is_idle());
108 CHECK(buf);
109 CHECK(buf_len);
110 CHECK(!callback.is_null());
112 // If we have data buffered, complete the IO immediately.
113 if (!response_body_.empty()) {
114 int bytes_read = 0;
115 while (!response_body_.empty() && buf_len > 0) {
116 scoped_refptr<IOBufferWithSize> data = response_body_.front();
117 const int bytes_to_copy = std::min(buf_len, data->size());
118 memcpy(&(buf->data()[bytes_read]), data->data(), bytes_to_copy);
119 buf_len -= bytes_to_copy;
120 if (bytes_to_copy == data->size()) {
121 response_body_.pop_front();
122 } else {
123 const int bytes_remaining = data->size() - bytes_to_copy;
124 IOBufferWithSize* new_buffer = new IOBufferWithSize(bytes_remaining);
125 memcpy(new_buffer->data(), &(data->data()[bytes_to_copy]),
126 bytes_remaining);
127 response_body_.pop_front();
128 response_body_.push_front(make_scoped_refptr(new_buffer));
130 bytes_read += bytes_to_copy;
132 stream_->IncreaseRecvWindowSize(bytes_read);
133 return bytes_read;
134 } else if (stream_->closed()) {
135 return stream_->response_status();
138 CHECK(callback_.is_null());
139 CHECK(!user_buffer_);
140 CHECK_EQ(0, user_buffer_len_);
142 callback_ = callback;
143 user_buffer_ = buf;
144 user_buffer_len_ = buf_len;
145 return ERR_IO_PENDING;
148 void SpdyHttpStream::Close(bool not_reusable) {
149 // Note: the not_reusable flag has no meaning for SPDY streams.
151 Cancel();
154 HttpStream* SpdyHttpStream::RenewStreamForAuth() {
155 return NULL;
158 bool SpdyHttpStream::IsResponseBodyComplete() const {
159 if (!stream_)
160 return false;
161 return stream_->closed();
164 bool SpdyHttpStream::CanFindEndOfResponse() const {
165 return true;
168 bool SpdyHttpStream::IsMoreDataBuffered() const {
169 return false;
172 bool SpdyHttpStream::IsConnectionReused() const {
173 return spdy_session_->IsReused();
176 void SpdyHttpStream::SetConnectionReused() {
177 // SPDY doesn't need an indicator here.
180 bool SpdyHttpStream::IsConnectionReusable() const {
181 // SPDY streams aren't considered reusable.
182 return false;
185 void SpdyHttpStream::set_chunk_callback(ChunkCallback* callback) {
186 if (request_body_stream_ != NULL)
187 request_body_stream_->set_chunk_callback(callback);
190 int SpdyHttpStream::SendRequest(const HttpRequestHeaders& request_headers,
191 UploadDataStream* request_body,
192 HttpResponseInfo* response,
193 const CompletionCallback& callback) {
194 base::Time request_time = base::Time::Now();
195 CHECK(stream_.get());
197 stream_->SetDelegate(this);
199 linked_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock);
200 CreateSpdyHeadersFromHttpRequest(*request_info_, request_headers,
201 headers.get(), stream_->GetProtocolVersion(),
202 direct_);
203 stream_->set_spdy_headers(headers);
205 stream_->SetRequestTime(request_time);
206 // This should only get called in the case of a request occurring
207 // during server push that has already begun but hasn't finished,
208 // so we set the response's request time to be the actual one
209 if (response_info_)
210 response_info_->request_time = request_time;
212 CHECK(!request_body_stream_.get());
213 if (request_body) {
214 if (request_body->size() || request_body->is_chunked()) {
215 request_body_stream_.reset(request_body);
216 // Use kMaxSpdyFrameChunkSize as the buffer size, since the request
217 // body data is written with this size at a time.
218 raw_request_body_buf_ = new IOBufferWithSize(kMaxSpdyFrameChunkSize);
219 // The request body buffer is empty at first.
220 request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_, 0);
221 } else {
222 delete request_body;
226 CHECK(!callback.is_null());
227 CHECK(!stream_->cancelled());
228 CHECK(response);
230 if (!stream_->pushed() && stream_->closed()) {
231 if (stream_->response_status() == OK)
232 return ERR_FAILED;
233 else
234 return stream_->response_status();
237 // SendRequest can be called in two cases.
239 // a) A client initiated request. In this case, |response_info_| should be
240 // NULL to start with.
241 // b) A client request which matches a response that the server has already
242 // pushed.
243 if (push_response_info_.get()) {
244 *response = *(push_response_info_.get());
245 push_response_info_.reset();
247 else
248 DCHECK_EQ(static_cast<HttpResponseInfo*>(NULL), response_info_);
250 response_info_ = response;
252 // Put the peer's IP address and port into the response.
253 AddressList address;
254 int result = stream_->GetPeerAddress(&address);
255 if (result != OK)
256 return result;
257 response_info_->socket_address = HostPortPair::FromAddrInfo(address.head());
259 bool has_upload_data = request_body_stream_.get() != NULL;
260 result = stream_->SendRequest(has_upload_data);
261 if (result == ERR_IO_PENDING) {
262 CHECK(callback_.is_null());
263 callback_ = callback;
265 return result;
268 void SpdyHttpStream::Cancel() {
269 if (spdy_session_)
270 spdy_session_->CancelPendingCreateStreams(&stream_);
271 callback_.Reset();
272 if (stream_)
273 stream_->Cancel();
276 bool SpdyHttpStream::OnSendHeadersComplete(int status) {
277 if (!callback_.is_null())
278 DoCallback(status);
279 return request_body_stream_.get() == NULL;
282 int SpdyHttpStream::OnSendBody() {
283 CHECK(request_body_stream_.get());
285 // TODO(satorux): Clean up the logic here. This behavior is weird. Reading
286 // of upload data should happen in OnSendBody(). crbug.com/113107.
288 // Nothing to send. This happens when OnSendBody() is first called.
289 // A read of the upload data stream is initiated in OnSendBodyComplete().
290 if (request_body_buf_->BytesRemaining() == 0)
291 return OK;
293 const bool eof = request_body_stream_->IsEOF();
294 return stream_->WriteStreamData(
295 request_body_buf_,
296 request_body_buf_->BytesRemaining(),
297 eof ? DATA_FLAG_FIN : DATA_FLAG_NONE);
300 int SpdyHttpStream::OnSendBodyComplete(int status, bool* eof) {
301 // |status| is the number of bytes written to the SPDY stream.
302 CHECK(request_body_stream_.get());
303 *eof = false;
305 if (status > 0) {
306 request_body_buf_->DidConsume(status);
307 if (request_body_buf_->BytesRemaining()) {
308 // Go back to OnSendBody() to send the remaining data.
309 return OK;
313 // Check if the entire body data has been sent.
314 *eof = (request_body_stream_->IsEOF() &&
315 !request_body_buf_->BytesRemaining());
316 if (*eof)
317 return OK;
319 // Read the data from the request body stream.
320 const int bytes_read = request_body_stream_->Read(
321 raw_request_body_buf_, raw_request_body_buf_->size());
322 if (request_body_stream_->is_chunked() && bytes_read == ERR_IO_PENDING)
323 return ERR_IO_PENDING;
324 // ERR_IO_PENDING with chunked encoding is the only possible error.
325 DCHECK_GE(bytes_read, 0);
327 request_body_buf_ = new DrainableIOBuffer(raw_request_body_buf_,
328 bytes_read);
329 return OK;
332 int SpdyHttpStream::OnResponseReceived(const SpdyHeaderBlock& response,
333 base::Time response_time,
334 int status) {
335 if (!response_info_) {
336 DCHECK(stream_->pushed());
337 push_response_info_.reset(new HttpResponseInfo);
338 response_info_ = push_response_info_.get();
341 // If the response is already received, these headers are too late.
342 if (response_headers_received_) {
343 LOG(WARNING) << "SpdyHttpStream headers received after response started.";
344 return OK;
347 // TODO(mbelshe): This is the time of all headers received, not just time
348 // to first byte.
349 response_info_->response_time = base::Time::Now();
351 if (!SpdyHeadersToHttpResponse(response, stream_->GetProtocolVersion(),
352 response_info_)) {
353 // We might not have complete headers yet.
354 return ERR_INCOMPLETE_SPDY_HEADERS;
357 response_headers_received_ = true;
358 // Don't store the SSLInfo in the response here, HttpNetworkTransaction
359 // will take care of that part.
360 SSLInfo ssl_info;
361 NextProto protocol_negotiated = kProtoUnknown;
362 stream_->GetSSLInfo(&ssl_info,
363 &response_info_->was_npn_negotiated,
364 &protocol_negotiated);
365 response_info_->npn_negotiated_protocol =
366 SSLClientSocket::NextProtoToString(protocol_negotiated);
367 response_info_->request_time = stream_->GetRequestTime();
368 response_info_->vary_data.Init(*request_info_, *response_info_->headers);
369 // TODO(ahendrickson): This is recorded after the entire SYN_STREAM control
370 // frame has been received and processed. Move to framer?
371 response_info_->response_time = response_time;
373 if (!callback_.is_null())
374 DoCallback(status);
376 return status;
379 void SpdyHttpStream::OnDataReceived(const char* data, int length) {
380 // SpdyStream won't call us with data if the header block didn't contain a
381 // valid set of headers. So we don't expect to not have headers received
382 // here.
383 DCHECK(response_headers_received_);
385 // Note that data may be received for a SpdyStream prior to the user calling
386 // ReadResponseBody(), therefore user_buffer_ may be NULL. This may often
387 // happen for server initiated streams.
388 DCHECK(!stream_->closed() || stream_->pushed());
389 if (length > 0) {
390 // Save the received data.
391 IOBufferWithSize* io_buffer = new IOBufferWithSize(length);
392 memcpy(io_buffer->data(), data, length);
393 response_body_.push_back(make_scoped_refptr(io_buffer));
395 if (user_buffer_) {
396 // Handing small chunks of data to the caller creates measurable overhead.
397 // We buffer data in short time-spans and send a single read notification.
398 ScheduleBufferedReadCallback();
403 void SpdyHttpStream::OnDataSent(int length) {
404 // For HTTP streams, no data is sent from the client while in the OPEN state,
405 // so it is never called.
406 NOTREACHED();
409 void SpdyHttpStream::OnClose(int status) {
410 bool invoked_callback = false;
411 if (status == net::OK) {
412 // We need to complete any pending buffered read now.
413 invoked_callback = DoBufferedReadCallback();
415 if (!invoked_callback && !callback_.is_null())
416 DoCallback(status);
419 void SpdyHttpStream::ScheduleBufferedReadCallback() {
420 // If there is already a scheduled DoBufferedReadCallback, don't issue
421 // another one. Mark that we have received more data and return.
422 if (buffered_read_callback_pending_) {
423 more_read_data_pending_ = true;
424 return;
427 more_read_data_pending_ = false;
428 buffered_read_callback_pending_ = true;
429 const base::TimeDelta kBufferTime = base::TimeDelta::FromMilliseconds(1);
430 MessageLoop::current()->PostDelayedTask(
431 FROM_HERE,
432 base::Bind(base::IgnoreResult(&SpdyHttpStream::DoBufferedReadCallback),
433 weak_factory_.GetWeakPtr()),
434 kBufferTime);
437 // Checks to see if we should wait for more buffered data before notifying
438 // the caller. Returns true if we should wait, false otherwise.
439 bool SpdyHttpStream::ShouldWaitForMoreBufferedData() const {
440 // If the response is complete, there is no point in waiting.
441 if (stream_->closed())
442 return false;
444 int bytes_buffered = 0;
445 std::list<scoped_refptr<IOBufferWithSize> >::const_iterator it;
446 for (it = response_body_.begin();
447 it != response_body_.end() && bytes_buffered < user_buffer_len_;
448 ++it)
449 bytes_buffered += (*it)->size();
451 return bytes_buffered < user_buffer_len_;
454 bool SpdyHttpStream::DoBufferedReadCallback() {
455 weak_factory_.InvalidateWeakPtrs();
456 buffered_read_callback_pending_ = false;
458 // If the transaction is cancelled or errored out, we don't need to complete
459 // the read.
460 if (!stream_ || stream_->response_status() != OK || stream_->cancelled())
461 return false;
463 // When more_read_data_pending_ is true, it means that more data has
464 // arrived since we started waiting. Wait a little longer and continue
465 // to buffer.
466 if (more_read_data_pending_ && ShouldWaitForMoreBufferedData()) {
467 ScheduleBufferedReadCallback();
468 return false;
471 int rv = 0;
472 if (user_buffer_) {
473 rv = ReadResponseBody(user_buffer_, user_buffer_len_, callback_);
474 CHECK_NE(rv, ERR_IO_PENDING);
475 user_buffer_ = NULL;
476 user_buffer_len_ = 0;
477 DoCallback(rv);
478 return true;
480 return false;
483 void SpdyHttpStream::DoCallback(int rv) {
484 CHECK_NE(rv, ERR_IO_PENDING);
485 CHECK(!callback_.is_null());
487 // Since Run may result in being called back, clear user_callback_ in advance.
488 CompletionCallback c = callback_;
489 callback_.Reset();
490 c.Run(rv);
493 void SpdyHttpStream::GetSSLInfo(SSLInfo* ssl_info) {
494 DCHECK(stream_);
495 bool using_npn;
496 NextProto protocol_negotiated = kProtoUnknown;
497 stream_->GetSSLInfo(ssl_info, &using_npn, &protocol_negotiated);
500 void SpdyHttpStream::GetSSLCertRequestInfo(
501 SSLCertRequestInfo* cert_request_info) {
502 DCHECK(stream_);
503 stream_->GetSSLCertRequestInfo(cert_request_info);
506 bool SpdyHttpStream::IsSpdyHttpStream() const {
507 return true;
510 void SpdyHttpStream::Drain(HttpNetworkSession* session) {
511 Close(false);
512 delete this;
515 } // namespace net