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

Side by Side Diff: net/spdy/spdy_stream.cc

Issue 17382012: [SPDY] Refactor SpdyStream's handling of response headers (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: More updates from rebase Created 7 years, 6 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
« no previous file with comments | « net/spdy/spdy_stream.h ('k') | net/spdy/spdy_stream_test_util.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/spdy/spdy_stream.h" 5 #include "net/spdy/spdy_stream.h"
6 6
7 #include <limits>
8
9 #include "base/bind.h" 7 #include "base/bind.h"
10 #include "base/compiler_specific.h" 8 #include "base/compiler_specific.h"
11 #include "base/logging.h" 9 #include "base/logging.h"
12 #include "base/message_loop.h" 10 #include "base/message_loop.h"
13 #include "base/strings/stringprintf.h" 11 #include "base/strings/stringprintf.h"
14 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_number_conversions.h"
15 #include "base/values.h" 13 #include "base/values.h"
16 #include "net/spdy/spdy_buffer_producer.h" 14 #include "net/spdy/spdy_buffer_producer.h"
17 #include "net/spdy/spdy_http_utils.h" 15 #include "net/spdy/spdy_http_utils.h"
18 #include "net/spdy/spdy_session.h" 16 #include "net/spdy/spdy_session.h"
(...skipping 18 matching lines...) Expand all
37 int32 delta, 35 int32 delta,
38 int32 window_size, 36 int32 window_size,
39 NetLog::LogLevel /* log_level */) { 37 NetLog::LogLevel /* log_level */) {
40 base::DictionaryValue* dict = new base::DictionaryValue(); 38 base::DictionaryValue* dict = new base::DictionaryValue();
41 dict->SetInteger("stream_id", stream_id); 39 dict->SetInteger("stream_id", stream_id);
42 dict->SetInteger("delta", delta); 40 dict->SetInteger("delta", delta);
43 dict->SetInteger("window_size", window_size); 41 dict->SetInteger("window_size", window_size);
44 return dict; 42 return dict;
45 } 43 }
46 44
47 bool ContainsUpperAscii(const std::string& str) { 45 bool ContainsUppercaseAscii(const std::string& str) {
48 for (std::string::const_iterator i(str.begin()); i != str.end(); ++i) { 46 for (std::string::const_iterator i(str.begin()); i != str.end(); ++i) {
49 if (*i >= 'A' && *i <= 'Z') { 47 if (*i >= 'A' && *i <= 'Z') {
50 return true; 48 return true;
51 } 49 }
52 } 50 }
53 return false; 51 return false;
54 } 52 }
55 53
56 } // namespace 54 } // namespace
57 55
(...skipping 24 matching lines...) Expand all
82 SpdyStream::SpdyStream(SpdyStreamType type, 80 SpdyStream::SpdyStream(SpdyStreamType type,
83 SpdySession* session, 81 SpdySession* session,
84 const std::string& path, 82 const std::string& path,
85 RequestPriority priority, 83 RequestPriority priority,
86 int32 initial_send_window_size, 84 int32 initial_send_window_size,
87 int32 initial_recv_window_size, 85 int32 initial_recv_window_size,
88 const BoundNetLog& net_log) 86 const BoundNetLog& net_log)
89 : type_(type), 87 : type_(type),
90 weak_ptr_factory_(this), 88 weak_ptr_factory_(this),
91 in_do_loop_(false), 89 in_do_loop_(false),
92 continue_buffering_data_(true), 90 continue_buffering_data_(type_ == SPDY_PUSH_STREAM),
93 stream_id_(0), 91 stream_id_(0),
94 path_(path), 92 path_(path),
95 priority_(priority), 93 priority_(priority),
96 slot_(0), 94 slot_(0),
97 send_stalled_by_flow_control_(false), 95 send_stalled_by_flow_control_(false),
98 send_window_size_(initial_send_window_size), 96 send_window_size_(initial_send_window_size),
99 recv_window_size_(initial_recv_window_size), 97 recv_window_size_(initial_recv_window_size),
100 unacked_recv_window_bytes_(0), 98 unacked_recv_window_bytes_(0),
101 response_received_(false),
102 session_(session), 99 session_(session),
103 delegate_(NULL), 100 delegate_(NULL),
104 send_status_( 101 send_status_(
105 (type_ == SPDY_PUSH_STREAM) ? 102 (type_ == SPDY_PUSH_STREAM) ?
106 NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND), 103 NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND),
107 request_time_(base::Time::Now()), 104 request_time_(base::Time::Now()),
108 response_(new SpdyHeaderBlock), 105 response_headers_status_(RESPONSE_HEADERS_ARE_INCOMPLETE),
109 io_state_((type_ == SPDY_PUSH_STREAM) ? STATE_OPEN : STATE_NONE), 106 io_state_((type_ == SPDY_PUSH_STREAM) ? STATE_OPEN : STATE_NONE),
110 response_status_(OK), 107 response_status_(OK),
111 net_log_(net_log), 108 net_log_(net_log),
112 send_bytes_(0), 109 send_bytes_(0),
113 recv_bytes_(0), 110 recv_bytes_(0),
114 domain_bound_cert_type_(CLIENT_CERT_INVALID_TYPE), 111 domain_bound_cert_type_(CLIENT_CERT_INVALID_TYPE),
115 just_completed_frame_type_(DATA), 112 just_completed_frame_type_(DATA),
116 just_completed_frame_size_(0) { 113 just_completed_frame_size_(0) {
117 CHECK(type_ == SPDY_BIDIRECTIONAL_STREAM || 114 CHECK(type_ == SPDY_BIDIRECTIONAL_STREAM ||
118 type_ == SPDY_REQUEST_RESPONSE_STREAM || 115 type_ == SPDY_REQUEST_RESPONSE_STREAM ||
119 type_ == SPDY_PUSH_STREAM); 116 type_ == SPDY_PUSH_STREAM);
120 } 117 }
121 118
122 SpdyStream::~SpdyStream() { 119 SpdyStream::~SpdyStream() {
123 CHECK(!in_do_loop_); 120 CHECK(!in_do_loop_);
124 UpdateHistograms(); 121 UpdateHistograms();
125 } 122 }
126 123
127 void SpdyStream::SetDelegate(Delegate* delegate) { 124 void SpdyStream::SetDelegate(Delegate* delegate) {
128 CHECK(!delegate_); 125 CHECK(!delegate_);
129 CHECK(delegate); 126 CHECK(delegate);
130 delegate_ = delegate; 127 delegate_ = delegate;
131 128
132 if (type_ == SPDY_PUSH_STREAM) { 129 if (type_ == SPDY_PUSH_STREAM) {
133 CHECK(response_received()); 130 DCHECK(continue_buffering_data_);
134 base::MessageLoop::current()->PostTask( 131 base::MessageLoop::current()->PostTask(
135 FROM_HERE, 132 FROM_HERE,
136 base::Bind(&SpdyStream::PushedStreamReplayData, GetWeakPtr())); 133 base::Bind(&SpdyStream::PushedStreamReplayData, GetWeakPtr()));
137 } else {
138 continue_buffering_data_ = false;
139 } 134 }
140 } 135 }
141 136
137 SpdyStream::Delegate* SpdyStream::GetDelegate() {
138 return delegate_;
139 }
140
142 void SpdyStream::PushedStreamReplayData() { 141 void SpdyStream::PushedStreamReplayData() {
142 DCHECK_EQ(type_, SPDY_PUSH_STREAM);
143 DCHECK_NE(stream_id_, 0u); 143 DCHECK_NE(stream_id_, 0u);
144 144 DCHECK(continue_buffering_data_);
145 if (!delegate_)
146 return;
147 145
148 continue_buffering_data_ = false; 146 continue_buffering_data_ = false;
149 147
150 // TODO(akalin): This call may delete this object. Figure out what 148 // The delegate methods called below may delete |this|, so use
151 // to do in that case. 149 // |weak_this| to detect that.
152 int rv = delegate_->OnResponseHeadersReceived(*response_, response_time_, OK); 150 base::WeakPtr<SpdyStream> weak_this = GetWeakPtr();
153 if (rv == ERR_INCOMPLETE_SPDY_HEADERS) { 151
154 // We don't have complete headers. Assume we're waiting for another 152 CHECK(delegate_);
155 // HEADERS frame. Since we don't have headers, we had better not have 153 SpdyResponseHeadersStatus status =
156 // any pending data frames. 154 delegate_->OnResponseHeadersUpdated(response_headers_);
157 if (pending_buffers_.size() != 0U) { 155 if (status == RESPONSE_HEADERS_ARE_INCOMPLETE) {
156 // Since RESPONSE_HEADERS_ARE_INCOMPLETE was returned, we must not
157 // have been closed. Since we don't have complete headers, assume
158 // we're waiting for another HEADERS frame, and we had better not
159 // have any pending data frames.
160 CHECK(weak_this);
161 if (!pending_buffers_.empty()) {
158 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, 162 LogStreamError(ERR_SPDY_PROTOCOL_ERROR,
159 "HEADERS incomplete headers, but pending data frames."); 163 "Data received with incomplete headers.");
160 session_->CloseActiveStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR); 164 session_->CloseActiveStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR);
161 } 165 }
162 return; 166 return;
163 } 167 }
164 168
165 std::vector<SpdyBuffer*> buffers; 169 // OnResponseHeadersUpdated() may have closed |this|.
166 pending_buffers_.release(&buffers); 170 if (!weak_this)
167 for (size_t i = 0; i < buffers.size(); ++i) { 171 return;
168 // It is always possible that a callback to the delegate results in 172
169 // the delegate no longer being available. 173 response_headers_status_ = RESPONSE_HEADERS_ARE_COMPLETE;
170 if (!delegate_) 174
175 while (!pending_buffers_.empty()) {
176 // Take ownership of the first element of |pending_buffers_|.
177 scoped_ptr<SpdyBuffer> buffer(pending_buffers_.front());
178 pending_buffers_.weak_erase(pending_buffers_.begin());
179
180 bool eof = (buffer == NULL);
181
182 CHECK(delegate_);
183 delegate_->OnDataReceived(buffer.Pass());
184
185 // OnDataReceived() may have closed |this|.
186 if (!weak_this)
187 return;
188
189 if (eof) {
190 DCHECK(pending_buffers_.empty());
191 session_->CloseActiveStream(stream_id_, OK);
192 DCHECK(!weak_this);
193 // |pending_buffers_| is invalid at this point.
171 break; 194 break;
172 if (buffers[i]) {
173 delegate_->OnDataReceived(scoped_ptr<SpdyBuffer>(buffers[i]));
174 } else {
175 delegate_->OnDataReceived(scoped_ptr<SpdyBuffer>());
176 session_->CloseActiveStream(stream_id_, OK);
177 // Note: |this| may be deleted after calling CloseActiveStream.
178 DCHECK_EQ(buffers.size() - 1, i);
179 } 195 }
180 } 196 }
181 } 197 }
182 198
183 scoped_ptr<SpdyFrame> SpdyStream::ProduceSynStreamFrame() { 199 scoped_ptr<SpdyFrame> SpdyStream::ProduceSynStreamFrame() {
184 CHECK_EQ(io_state_, STATE_SEND_REQUEST_HEADERS_COMPLETE); 200 CHECK_EQ(io_state_, STATE_SEND_REQUEST_HEADERS_COMPLETE);
185 CHECK(request_); 201 CHECK(request_headers_);
186 CHECK_GT(stream_id_, 0u); 202 CHECK_GT(stream_id_, 0u);
187 203
188 SpdyControlFlags flags = 204 SpdyControlFlags flags =
189 (send_status_ == NO_MORE_DATA_TO_SEND) ? 205 (send_status_ == NO_MORE_DATA_TO_SEND) ?
190 CONTROL_FLAG_FIN : CONTROL_FLAG_NONE; 206 CONTROL_FLAG_FIN : CONTROL_FLAG_NONE;
191 scoped_ptr<SpdyFrame> frame(session_->CreateSynStream( 207 scoped_ptr<SpdyFrame> frame(session_->CreateSynStream(
192 stream_id_, priority_, slot_, flags, *request_)); 208 stream_id_, priority_, slot_, flags, *request_headers_));
193 send_time_ = base::TimeTicks::Now(); 209 send_time_ = base::TimeTicks::Now();
194 return frame.Pass(); 210 return frame.Pass();
195 } 211 }
196 212
197 void SpdyStream::DetachDelegate() { 213 void SpdyStream::DetachDelegate() {
198 CHECK(!in_do_loop_); 214 CHECK(!in_do_loop_);
199 DCHECK(!closed()); 215 DCHECK(!closed());
200 delegate_ = NULL; 216 delegate_ = NULL;
201 Cancel(); 217 Cancel();
202 } 218 }
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
366 } 382 }
367 383
368 base::Time SpdyStream::GetRequestTime() const { 384 base::Time SpdyStream::GetRequestTime() const {
369 return request_time_; 385 return request_time_;
370 } 386 }
371 387
372 void SpdyStream::SetRequestTime(base::Time t) { 388 void SpdyStream::SetRequestTime(base::Time t) {
373 request_time_ = t; 389 request_time_ = t;
374 } 390 }
375 391
376 int SpdyStream::OnResponseHeadersReceived(const SpdyHeaderBlock& response) { 392 int SpdyStream::OnInitialResponseHeadersReceived(
377 int rv = OK; 393 const SpdyHeaderBlock& initial_response_headers,
378 394 base::Time response_time,
379 metrics_.StartStream(); 395 base::TimeTicks recv_first_byte_time) {
380 396 // SpdySession guarantees that this is called at most once.
381 // TODO(akalin): This should be handled as a protocol error. 397 CHECK(response_headers_.empty());
382 DCHECK(response_->empty());
383 *response_ = response; // TODO(ukai): avoid copy.
384
385 recv_first_byte_time_ = base::TimeTicks::Now();
386 response_time_ = base::Time::Now();
387 398
388 // Check to make sure that we don't receive the response headers 399 // Check to make sure that we don't receive the response headers
389 // before we're ready for it. 400 // before we're ready for it.
390 switch (type_) { 401 switch (type_) {
391 case SPDY_BIDIRECTIONAL_STREAM: 402 case SPDY_BIDIRECTIONAL_STREAM:
392 // For a bidirectional stream, we're ready for the response 403 // For a bidirectional stream, we're ready for the response
393 // headers once we've finished sending the request headers. 404 // headers once we've finished sending the request headers.
394 if (io_state_ < STATE_OPEN) 405 if (io_state_ < STATE_OPEN)
395 return ERR_SPDY_PROTOCOL_ERROR; 406 return ERR_SPDY_PROTOCOL_ERROR;
396 break; 407 break;
397 408
398 case SPDY_REQUEST_RESPONSE_STREAM: 409 case SPDY_REQUEST_RESPONSE_STREAM:
399 // For a request/response stream, we're ready for the response 410 // For a request/response stream, we're ready for the response
400 // headers once we've finished sending the request headers and 411 // headers once we've finished sending the request headers and
401 // the request body (if we have one). 412 // the request body (if we have one).
402 if ((io_state_ < STATE_OPEN) || (send_status_ == MORE_DATA_TO_SEND) || 413 if ((io_state_ < STATE_OPEN) || (send_status_ == MORE_DATA_TO_SEND) ||
403 pending_send_data_.get()) 414 pending_send_data_.get())
404 return ERR_SPDY_PROTOCOL_ERROR; 415 return ERR_SPDY_PROTOCOL_ERROR;
405 break; 416 break;
406 417
407 case SPDY_PUSH_STREAM: 418 case SPDY_PUSH_STREAM:
408 // For a push stream, we're ready immediately. 419 // For a push stream, we're ready immediately.
409 DCHECK_EQ(send_status_, NO_MORE_DATA_TO_SEND); 420 DCHECK_EQ(send_status_, NO_MORE_DATA_TO_SEND);
410 DCHECK_EQ(io_state_, STATE_OPEN); 421 DCHECK_EQ(io_state_, STATE_OPEN);
411 break; 422 break;
412 } 423 }
413 424
425 metrics_.StartStream();
426
414 DCHECK_EQ(io_state_, STATE_OPEN); 427 DCHECK_EQ(io_state_, STATE_OPEN);
415 428
416 // TODO(akalin): Merge the code below with the code in OnHeaders(). 429 response_time_ = response_time;
417 430 recv_first_byte_time_ = recv_first_byte_time;
418 // Append all the headers into the response header block. 431 return MergeWithResponseHeaders(initial_response_headers);
419 for (SpdyHeaderBlock::const_iterator it = response.begin();
420 it != response.end(); ++it) {
421 // Disallow uppercase headers.
422 if (ContainsUpperAscii(it->first)) {
423 session_->ResetStream(stream_id_, priority_, RST_STREAM_PROTOCOL_ERROR,
424 "Upper case characters in header: " + it->first);
425 return ERR_SPDY_PROTOCOL_ERROR;
426 }
427 }
428
429 if ((*response_).find("transfer-encoding") != (*response_).end()) {
430 session_->ResetStream(stream_id_, priority_, RST_STREAM_PROTOCOL_ERROR,
431 "Received transfer-encoding header");
432 return ERR_SPDY_PROTOCOL_ERROR;
433 }
434
435 if (delegate_) {
436 // May delete this object.
437 rv = delegate_->OnResponseHeadersReceived(*response_, response_time_, rv);
438 }
439 // If delegate_ is not yet attached, we'll call
440 // OnResponseHeadersReceived after the delegate gets attached to the
441 // stream.
442
443 return rv;
444 } 432 }
445 433
446 int SpdyStream::OnHeaders(const SpdyHeaderBlock& headers) { 434 int SpdyStream::OnAdditionalResponseHeadersReceived(
447 DCHECK(!response_->empty()); 435 const SpdyHeaderBlock& additional_response_headers) {
448 436 if (type_ == SPDY_REQUEST_RESPONSE_STREAM) {
449 // Append all the headers into the response header block. 437 LOG(WARNING) << "Additional headers received for request/response stream";
450 for (SpdyHeaderBlock::const_iterator it = headers.begin(); 438 return OK;
451 it != headers.end(); ++it) { 439 } else if (type_ == SPDY_PUSH_STREAM &&
452 // Disallow duplicate headers. This is just to be conservative. 440 response_headers_status_ == RESPONSE_HEADERS_ARE_COMPLETE) {
453 if ((*response_).find(it->first) != (*response_).end()) { 441 LOG(WARNING) << "Additional headers received for push stream";
454 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, "HEADERS duplicate header"); 442 return OK;
455 response_status_ = ERR_SPDY_PROTOCOL_ERROR;
456 return ERR_SPDY_PROTOCOL_ERROR;
457 }
458
459 // Disallow uppercase headers.
460 if (ContainsUpperAscii(it->first)) {
461 session_->ResetStream(stream_id_, priority_, RST_STREAM_PROTOCOL_ERROR,
462 "Upper case characters in header: " + it->first);
463 return ERR_SPDY_PROTOCOL_ERROR;
464 }
465
466 (*response_)[it->first] = it->second;
467 } 443 }
468 444 return MergeWithResponseHeaders(additional_response_headers);
469 if ((*response_).find("transfer-encoding") != (*response_).end()) {
470 session_->ResetStream(stream_id_, priority_, RST_STREAM_PROTOCOL_ERROR,
471 "Received transfer-encoding header");
472 return ERR_SPDY_PROTOCOL_ERROR;
473 }
474
475 int rv = OK;
476 if (delegate_) {
477 // May delete this object.
478 rv = delegate_->OnResponseHeadersReceived(*response_, response_time_, rv);
479 // ERR_INCOMPLETE_SPDY_HEADERS means that we are waiting for more
480 // headers before the response header block is complete.
481 if (rv == ERR_INCOMPLETE_SPDY_HEADERS)
482 rv = OK;
483 }
484 return rv;
485 } 445 }
486 446
487 void SpdyStream::OnDataReceived(scoped_ptr<SpdyBuffer> buffer) { 447 void SpdyStream::OnDataReceived(scoped_ptr<SpdyBuffer> buffer) {
488 DCHECK(session_->IsStreamActive(stream_id_)); 448 DCHECK(session_->IsStreamActive(stream_id_));
489 // If we don't have a response, then the SYN_REPLY did not come through.
490 // We cannot pass data up to the caller unless the reply headers have been
491 // received.
492 if (!response_received()) {
493 LogStreamError(ERR_SYN_REPLY_NOT_RECEIVED, "Didn't receive a response.");
494 session_->CloseActiveStream(stream_id_, ERR_SYN_REPLY_NOT_RECEIVED);
495 return;
496 }
497 449
450 // If we're still buffering data for a push stream, we will do the
451 // check for data received with incomplete headers in
452 // PushedStreamReplayData().
498 if (!delegate_ || continue_buffering_data_) { 453 if (!delegate_ || continue_buffering_data_) {
454 DCHECK_EQ(type_, SPDY_PUSH_STREAM);
499 // It should be valid for this to happen in the server push case. 455 // It should be valid for this to happen in the server push case.
500 // We'll return received data when delegate gets attached to the stream. 456 // We'll return received data when delegate gets attached to the stream.
501 if (buffer) { 457 if (buffer) {
502 pending_buffers_.push_back(buffer.release()); 458 pending_buffers_.push_back(buffer.release());
503 } else { 459 } else {
504 pending_buffers_.push_back(NULL); 460 pending_buffers_.push_back(NULL);
505 metrics_.StopStream(); 461 metrics_.StopStream();
506 // Note: we leave the stream open in the session until the stream 462 // Note: we leave the stream open in the session until the stream
507 // is claimed. 463 // is claimed.
508 } 464 }
509 return; 465 return;
510 } 466 }
511 467
468 // If we have response headers but the delegate has indicated that
469 // it's still incomplete, then that's a protocol error.
470 if (response_headers_status_ == RESPONSE_HEADERS_ARE_INCOMPLETE) {
471 LogStreamError(ERR_SPDY_PROTOCOL_ERROR,
472 "Data received with incomplete headers.");
473 session_->CloseActiveStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR);
474 return;
475 }
476
512 CHECK(!closed()); 477 CHECK(!closed());
513 478
514 if (!buffer) { 479 if (!buffer) {
515 metrics_.StopStream(); 480 metrics_.StopStream();
481 // Deletes |this|.
516 session_->CloseActiveStream(stream_id_, OK); 482 session_->CloseActiveStream(stream_id_, OK);
517 // Note: |this| may be deleted after calling CloseActiveStream.
518 return; 483 return;
519 } 484 }
520 485
521 size_t length = buffer->GetRemainingSize(); 486 size_t length = buffer->GetRemainingSize();
522 DCHECK_LE(length, session_->GetDataFrameMaximumPayload()); 487 DCHECK_LE(length, session_->GetDataFrameMaximumPayload());
523 if (session_->flow_control_state() >= SpdySession::FLOW_CONTROL_STREAM) { 488 if (session_->flow_control_state() >= SpdySession::FLOW_CONTROL_STREAM) {
524 DecreaseRecvWindowSize(static_cast<int32>(length)); 489 DecreaseRecvWindowSize(static_cast<int32>(length));
525 buffer->AddConsumeCallback( 490 buffer->AddConsumeCallback(
526 base::Bind(&SpdyStream::OnReadBufferConsumed, GetWeakPtr())); 491 base::Bind(&SpdyStream::OnReadBufferConsumed, GetWeakPtr()));
527 } 492 }
528 493
529 // Track our bandwidth. 494 // Track our bandwidth.
530 metrics_.RecordBytes(length); 495 metrics_.RecordBytes(length);
531 recv_bytes_ += length; 496 recv_bytes_ += length;
532 recv_last_byte_time_ = base::TimeTicks::Now(); 497 recv_last_byte_time_ = base::TimeTicks::Now();
533 498
534 if (delegate_->OnDataReceived(buffer.Pass()) != OK) { 499 // May close |this|.
535 // |delegate_| rejected the data. 500 delegate_->OnDataReceived(buffer.Pass());
536 LogStreamError(ERR_SPDY_PROTOCOL_ERROR, "Delegate rejected the data");
537 session_->CloseActiveStream(stream_id_, ERR_SPDY_PROTOCOL_ERROR);
538 return;
539 }
540 } 501 }
541 502
542 void SpdyStream::OnFrameWriteComplete(SpdyFrameType frame_type, 503 void SpdyStream::OnFrameWriteComplete(SpdyFrameType frame_type,
543 size_t frame_size) { 504 size_t frame_size) {
544 if (frame_size < session_->GetFrameMinimumSize() || 505 if (frame_size < session_->GetFrameMinimumSize() ||
545 frame_size > session_->GetFrameMaximumSize()) { 506 frame_size > session_->GetFrameMaximumSize()) {
546 NOTREACHED(); 507 NOTREACHED();
547 return; 508 return;
548 } 509 }
549 if (closed()) 510 if (closed())
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
585 546
586 void SpdyStream::Close() { 547 void SpdyStream::Close() {
587 CHECK(!in_do_loop_); 548 CHECK(!in_do_loop_);
588 if (stream_id_ != 0) { 549 if (stream_id_ != 0) {
589 session_->CloseActiveStream(stream_id_, OK); 550 session_->CloseActiveStream(stream_id_, OK);
590 } else { 551 } else {
591 session_->CloseCreatedStream(GetWeakPtr(), OK); 552 session_->CloseCreatedStream(GetWeakPtr(), OK);
592 } 553 }
593 } 554 }
594 555
595 int SpdyStream::SendRequestHeaders(scoped_ptr<SpdyHeaderBlock> headers, 556 int SpdyStream::SendRequestHeaders(scoped_ptr<SpdyHeaderBlock> request_headers,
596 SpdySendStatus send_status) { 557 SpdySendStatus send_status) {
597 CHECK_NE(type_, SPDY_PUSH_STREAM); 558 CHECK_NE(type_, SPDY_PUSH_STREAM);
598 CHECK_EQ(send_status_, MORE_DATA_TO_SEND); 559 CHECK_EQ(send_status_, MORE_DATA_TO_SEND);
599 CHECK(!request_); 560 CHECK(!request_headers_);
600 CHECK(!pending_send_data_.get()); 561 CHECK(!pending_send_data_.get());
601 CHECK_EQ(io_state_, STATE_NONE); 562 CHECK_EQ(io_state_, STATE_NONE);
602 request_ = headers.Pass(); 563 request_headers_ = request_headers.Pass();
603 send_status_ = send_status; 564 send_status_ = send_status;
604 io_state_ = STATE_GET_DOMAIN_BOUND_CERT; 565 io_state_ = STATE_GET_DOMAIN_BOUND_CERT;
605 return DoLoop(OK); 566 return DoLoop(OK);
606 } 567 }
607 568
608 void SpdyStream::SendData(IOBuffer* data, 569 void SpdyStream::SendData(IOBuffer* data,
609 int length, 570 int length,
610 SpdySendStatus send_status) { 571 SpdySendStatus send_status) {
611 CHECK_NE(type_, SPDY_PUSH_STREAM); 572 CHECK_NE(type_, SPDY_PUSH_STREAM);
612 CHECK_EQ(send_status_, MORE_DATA_TO_SEND); 573 CHECK_EQ(send_status_, MORE_DATA_TO_SEND);
(...skipping 25 matching lines...) Expand all
638 NetLog::IntegerCallback("stream_id", stream_id_)); 599 NetLog::IntegerCallback("stream_id", stream_id_));
639 send_stalled_by_flow_control_ = false; 600 send_stalled_by_flow_control_ = false;
640 QueueNextDataFrame(); 601 QueueNextDataFrame();
641 } 602 }
642 } 603 }
643 604
644 base::WeakPtr<SpdyStream> SpdyStream::GetWeakPtr() { 605 base::WeakPtr<SpdyStream> SpdyStream::GetWeakPtr() {
645 return weak_ptr_factory_.GetWeakPtr(); 606 return weak_ptr_factory_.GetWeakPtr();
646 } 607 }
647 608
648 bool SpdyStream::HasUrl() const {
649 if (type_ == SPDY_PUSH_STREAM)
650 return response_received();
651 return request_ != NULL;
652 }
653
654 GURL SpdyStream::GetUrl() const {
655 DCHECK(HasUrl());
656
657 const SpdyHeaderBlock& headers =
658 (type_ == SPDY_PUSH_STREAM) ? *response_ : *request_;
659 return GetUrlFromHeaderBlock(headers, GetProtocolVersion(),
660 type_ == SPDY_PUSH_STREAM);
661 }
662
663 bool SpdyStream::GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const { 609 bool SpdyStream::GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const {
664 if (stream_id_ == 0) 610 if (stream_id_ == 0)
665 return false; 611 return false;
666 612
667 return session_->GetLoadTimingInfo(stream_id_, load_timing_info); 613 return session_->GetLoadTimingInfo(stream_id_, load_timing_info);
668 } 614 }
669 615
616 GURL SpdyStream::GetUrl() const {
617 if (type_ != SPDY_PUSH_STREAM && !request_headers_)
618 return GURL();
619
620 const SpdyHeaderBlock& headers =
621 (type_ == SPDY_PUSH_STREAM) ? response_headers_ : *request_headers_;
622 return GetUrlFromHeaderBlock(headers, GetProtocolVersion(),
623 type_ == SPDY_PUSH_STREAM);
624 }
625
626 bool SpdyStream::HasUrl() const {
627 return !GetUrl().is_empty();
628 }
629
670 void SpdyStream::OnGetDomainBoundCertComplete(int result) { 630 void SpdyStream::OnGetDomainBoundCertComplete(int result) {
671 DCHECK_EQ(io_state_, STATE_GET_DOMAIN_BOUND_CERT_COMPLETE); 631 DCHECK_EQ(io_state_, STATE_GET_DOMAIN_BOUND_CERT_COMPLETE);
672 DoLoop(result); 632 DoLoop(result);
673 } 633 }
674 634
675 int SpdyStream::DoLoop(int result) { 635 int SpdyStream::DoLoop(int result) {
676 CHECK(!in_do_loop_); 636 CHECK(!in_do_loop_);
677 in_do_loop_ = true; 637 in_do_loop_ = true;
678 638
679 do { 639 do {
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
727 } while (result != ERR_IO_PENDING && io_state_ != STATE_NONE && 687 } while (result != ERR_IO_PENDING && io_state_ != STATE_NONE &&
728 io_state_ != STATE_OPEN); 688 io_state_ != STATE_OPEN);
729 689
730 CHECK(in_do_loop_); 690 CHECK(in_do_loop_);
731 in_do_loop_ = false; 691 in_do_loop_ = false;
732 692
733 return result; 693 return result;
734 } 694 }
735 695
736 int SpdyStream::DoGetDomainBoundCert() { 696 int SpdyStream::DoGetDomainBoundCert() {
737 CHECK(request_); 697 CHECK(request_headers_);
738 DCHECK_NE(type_, SPDY_PUSH_STREAM); 698 DCHECK_NE(type_, SPDY_PUSH_STREAM);
739 GURL url = GetUrl(); 699 GURL url = GetUrl();
740 if (!session_->NeedsCredentials() || !url.SchemeIs("https")) { 700 if (!session_->NeedsCredentials() || !url.SchemeIs("https")) {
741 // Proceed directly to sending the request headers 701 // Proceed directly to sending the request headers
742 io_state_ = STATE_SEND_REQUEST_HEADERS; 702 io_state_ = STATE_SEND_REQUEST_HEADERS;
743 return OK; 703 return OK;
744 } 704 }
745 705
746 slot_ = session_->credential_state()->FindCredentialSlot(GetUrl()); 706 slot_ = session_->credential_state()->FindCredentialSlot(GetUrl());
747 if (slot_ != SpdyCredentialState::kNoEntry) { 707 if (slot_ != SpdyCredentialState::kNoEntry) {
(...skipping 19 matching lines...) Expand all
767 DCHECK_NE(type_, SPDY_PUSH_STREAM); 727 DCHECK_NE(type_, SPDY_PUSH_STREAM);
768 if (result != OK) 728 if (result != OK)
769 return result; 729 return result;
770 730
771 io_state_ = STATE_SEND_DOMAIN_BOUND_CERT; 731 io_state_ = STATE_SEND_DOMAIN_BOUND_CERT;
772 slot_ = session_->credential_state()->SetHasCredential(GetUrl()); 732 slot_ = session_->credential_state()->SetHasCredential(GetUrl());
773 return OK; 733 return OK;
774 } 734 }
775 735
776 int SpdyStream::DoSendDomainBoundCert() { 736 int SpdyStream::DoSendDomainBoundCert() {
777 CHECK(request_); 737 CHECK(request_headers_);
778 DCHECK_NE(type_, SPDY_PUSH_STREAM); 738 DCHECK_NE(type_, SPDY_PUSH_STREAM);
779 io_state_ = STATE_SEND_DOMAIN_BOUND_CERT_COMPLETE; 739 io_state_ = STATE_SEND_DOMAIN_BOUND_CERT_COMPLETE;
780 740
781 std::string origin = GetUrl().GetOrigin().spec(); 741 std::string origin = GetUrl().GetOrigin().spec();
782 DCHECK(origin[origin.length() - 1] == '/'); 742 DCHECK(origin[origin.length() - 1] == '/');
783 origin.erase(origin.length() - 1); // Trim trailing slash. 743 origin.erase(origin.length() - 1); // Trim trailing slash.
784 scoped_ptr<SpdyFrame> frame; 744 scoped_ptr<SpdyFrame> frame;
785 int rv = session_->CreateCredentialFrame( 745 int rv = session_->CreateCredentialFrame(
786 origin, domain_bound_cert_type_, domain_bound_private_key_, 746 origin, domain_bound_cert_type_, domain_bound_private_key_,
787 domain_bound_cert_, priority_, &frame); 747 domain_bound_cert_, priority_, &frame);
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
859 819
860 } // namespace 820 } // namespace
861 821
862 int SpdyStream::DoSendRequestHeadersComplete() { 822 int SpdyStream::DoSendRequestHeadersComplete() {
863 DCHECK_NE(type_, SPDY_PUSH_STREAM); 823 DCHECK_NE(type_, SPDY_PUSH_STREAM);
864 DCHECK_EQ(just_completed_frame_type_, SYN_STREAM); 824 DCHECK_EQ(just_completed_frame_type_, SYN_STREAM);
865 DCHECK_NE(stream_id_, 0u); 825 DCHECK_NE(stream_id_, 0u);
866 826
867 io_state_ = STATE_OPEN; 827 io_state_ = STATE_OPEN;
868 828
869 // Do this before calling into the |delegate_| as that call may
870 // delete us.
871 int result = GetOpenStateResult(type_, send_status_);
872
873 CHECK(delegate_); 829 CHECK(delegate_);
830 // Must not close |this|; if it does, it will trigger the |in_do_loop_|
831 // check in the destructor.
874 delegate_->OnRequestHeadersSent(); 832 delegate_->OnRequestHeadersSent();
875 833
876 return result; 834 return GetOpenStateResult(type_, send_status_);
877 } 835 }
878 836
879 int SpdyStream::DoOpen() { 837 int SpdyStream::DoOpen() {
880 DCHECK_NE(type_, SPDY_PUSH_STREAM); 838 DCHECK_NE(type_, SPDY_PUSH_STREAM);
881 839
882 if (just_completed_frame_type_ != DATA) { 840 if (just_completed_frame_type_ != DATA) {
883 NOTREACHED(); 841 NOTREACHED();
884 return ERR_UNEXPECTED; 842 return ERR_UNEXPECTED;
885 } 843 }
886 844
(...skipping 15 matching lines...) Expand all
902 send_bytes_ += frame_payload_size; 860 send_bytes_ += frame_payload_size;
903 861
904 pending_send_data_->DidConsume(frame_payload_size); 862 pending_send_data_->DidConsume(frame_payload_size);
905 if (pending_send_data_->BytesRemaining() > 0) { 863 if (pending_send_data_->BytesRemaining() > 0) {
906 QueueNextDataFrame(); 864 QueueNextDataFrame();
907 return ERR_IO_PENDING; 865 return ERR_IO_PENDING;
908 } 866 }
909 867
910 pending_send_data_ = NULL; 868 pending_send_data_ = NULL;
911 869
912 // Do this before calling into the |delegate_| as that call may
913 // delete us.
914 int result = GetOpenStateResult(type_, send_status_);
915
916 CHECK(delegate_); 870 CHECK(delegate_);
871 // Must not close |this|; if it does, it will trigger the
872 // |in_do_loop_| check in the destructor.
917 delegate_->OnDataSent(); 873 delegate_->OnDataSent();
918 874
919 return result; 875 return GetOpenStateResult(type_, send_status_);
920 } 876 }
921 877
922 void SpdyStream::UpdateHistograms() { 878 void SpdyStream::UpdateHistograms() {
923 // We need at least the receive timers to be filled in, as otherwise 879 // We need at least the receive timers to be filled in, as otherwise
924 // metrics can be bogus. 880 // metrics can be bogus.
925 if (recv_first_byte_time_.is_null() || recv_last_byte_time_.is_null()) 881 if (recv_first_byte_time_.is_null() || recv_last_byte_time_.is_null())
926 return; 882 return;
927 883
928 base::TimeTicks effective_send_time; 884 base::TimeTicks effective_send_time;
929 if (type_ == SPDY_PUSH_STREAM) { 885 if (type_ == SPDY_PUSH_STREAM) {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
983 base::Bind(&SpdyStream::OnWriteBufferConsumed, 939 base::Bind(&SpdyStream::OnWriteBufferConsumed,
984 GetWeakPtr(), payload_size)); 940 GetWeakPtr(), payload_size));
985 } 941 }
986 942
987 session_->EnqueueStreamWrite( 943 session_->EnqueueStreamWrite(
988 GetWeakPtr(), DATA, 944 GetWeakPtr(), DATA,
989 scoped_ptr<SpdyBufferProducer>( 945 scoped_ptr<SpdyBufferProducer>(
990 new SimpleBufferProducer(data_buffer.Pass()))); 946 new SimpleBufferProducer(data_buffer.Pass())));
991 } 947 }
992 948
949 int SpdyStream::MergeWithResponseHeaders(
950 const SpdyHeaderBlock& new_response_headers) {
951 if (new_response_headers.find("transfer-encoding") !=
952 new_response_headers.end()) {
953 session_->ResetStream(stream_id_, priority_, RST_STREAM_PROTOCOL_ERROR,
954 "Received transfer-encoding header");
955 return ERR_SPDY_PROTOCOL_ERROR;
956 }
957
958 for (SpdyHeaderBlock::const_iterator it = new_response_headers.begin();
959 it != new_response_headers.end(); ++it) {
960 // Disallow uppercase headers.
961 if (ContainsUppercaseAscii(it->first)) {
962 session_->ResetStream(stream_id_, priority_, RST_STREAM_PROTOCOL_ERROR,
963 "Upper case characters in header: " + it->first);
964 return ERR_SPDY_PROTOCOL_ERROR;
965 }
966
967 SpdyHeaderBlock::iterator it2 = response_headers_.lower_bound(it->first);
968 // Disallow duplicate headers. This is just to be conservative.
969 if (it2 != response_headers_.end() && it2->first == it->first) {
970 session_->ResetStream(stream_id_, priority_, RST_STREAM_PROTOCOL_ERROR,
971 "Duplicate header: " + it->first);
972 return ERR_SPDY_PROTOCOL_ERROR;
973 }
974
975 response_headers_.insert(it2, *it);
976 }
977
978 // If delegate_ is not yet attached, we'll call
979 // OnResponseHeadersUpdated() after the delegate gets attached to
980 // the stream.
981 if (delegate_) {
982 // The call to OnResponseHeadersUpdated() below may delete |this|,
983 // so use |weak_this| to detect that.
984 base::WeakPtr<SpdyStream> weak_this = GetWeakPtr();
985
986 SpdyResponseHeadersStatus status =
987 delegate_->OnResponseHeadersUpdated(response_headers_);
988 if (status == RESPONSE_HEADERS_ARE_INCOMPLETE) {
989 // Since RESPONSE_HEADERS_ARE_INCOMPLETE was returned, we must not
990 // have been closed.
991 CHECK(weak_this);
992 // Incomplete headers are OK only for push streams.
993 if (type_ != SPDY_PUSH_STREAM)
994 return ERR_INCOMPLETE_SPDY_HEADERS;
995 } else if (weak_this) {
996 response_headers_status_ = RESPONSE_HEADERS_ARE_COMPLETE;
997 }
998 }
999
1000 return OK;
1001 }
1002
993 } // namespace net 1003 } // namespace net
OLDNEW
« no previous file with comments | « net/spdy/spdy_stream.h ('k') | net/spdy/spdy_stream_test_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698