| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 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/quic/quic_spdy_stream.h" | |
| 6 | |
| 7 #include <utility> | |
| 8 | |
| 9 #include "base/logging.h" | |
| 10 #include "base/strings/string_number_conversions.h" | |
| 11 #include "net/quic/quic_bug_tracker.h" | |
| 12 #include "net/quic/quic_spdy_session.h" | |
| 13 #include "net/quic/quic_utils.h" | |
| 14 #include "net/quic/quic_write_blocked_list.h" | |
| 15 #include "net/quic/spdy_utils.h" | |
| 16 | |
| 17 using base::IntToString; | |
| 18 using base::StringPiece; | |
| 19 using std::min; | |
| 20 using std::string; | |
| 21 | |
| 22 namespace net { | |
| 23 | |
| 24 #define ENDPOINT \ | |
| 25 (session()->perspective() == Perspective::IS_SERVER ? "Server: " : "Client:" \ | |
| 26 " ") | |
| 27 | |
| 28 QuicSpdyStream::QuicSpdyStream(QuicStreamId id, QuicSpdySession* spdy_session) | |
| 29 : ReliableQuicStream(id, spdy_session), | |
| 30 spdy_session_(spdy_session), | |
| 31 visitor_(nullptr), | |
| 32 headers_decompressed_(false), | |
| 33 priority_(kDefaultPriority), | |
| 34 trailers_decompressed_(false), | |
| 35 trailers_delivered_(false) { | |
| 36 DCHECK_NE(kCryptoStreamId, id); | |
| 37 // Don't receive any callbacks from the sequencer until headers | |
| 38 // are complete. | |
| 39 sequencer()->SetBlockedUntilFlush(); | |
| 40 spdy_session_->RegisterStreamPriority(id, priority_); | |
| 41 } | |
| 42 | |
| 43 QuicSpdyStream::~QuicSpdyStream() { | |
| 44 if (spdy_session_ != nullptr) { | |
| 45 spdy_session_->UnregisterStreamPriority(id()); | |
| 46 } | |
| 47 } | |
| 48 | |
| 49 void QuicSpdyStream::CloseWriteSide() { | |
| 50 if (!fin_received() && !rst_received() && sequencer()->ignore_read_data() && | |
| 51 !rst_sent()) { | |
| 52 DCHECK(fin_sent()); | |
| 53 // Tell the peer to stop sending further data. | |
| 54 DVLOG(1) << ENDPOINT << "Send QUIC_STREAM_NO_ERROR on stream " << id(); | |
| 55 Reset(QUIC_STREAM_NO_ERROR); | |
| 56 } | |
| 57 | |
| 58 ReliableQuicStream::CloseWriteSide(); | |
| 59 } | |
| 60 | |
| 61 void QuicSpdyStream::StopReading() { | |
| 62 if (!fin_received() && !rst_received() && write_side_closed() && | |
| 63 !rst_sent()) { | |
| 64 DCHECK(fin_sent()); | |
| 65 // Tell the peer to stop sending further data. | |
| 66 DVLOG(1) << ENDPOINT << "Send QUIC_STREAM_NO_ERROR on stream " << id(); | |
| 67 Reset(QUIC_STREAM_NO_ERROR); | |
| 68 } | |
| 69 ReliableQuicStream::StopReading(); | |
| 70 } | |
| 71 | |
| 72 size_t QuicSpdyStream::WriteHeaders( | |
| 73 SpdyHeaderBlock header_block, | |
| 74 bool fin, | |
| 75 QuicAckListenerInterface* ack_notifier_delegate) { | |
| 76 size_t bytes_written = spdy_session_->WriteHeaders( | |
| 77 id(), std::move(header_block), fin, priority_, ack_notifier_delegate); | |
| 78 if (fin) { | |
| 79 // TODO(rch): Add test to ensure fin_sent_ is set whenever a fin is sent. | |
| 80 set_fin_sent(true); | |
| 81 CloseWriteSide(); | |
| 82 } | |
| 83 return bytes_written; | |
| 84 } | |
| 85 | |
| 86 void QuicSpdyStream::WriteOrBufferBody( | |
| 87 const string& data, | |
| 88 bool fin, | |
| 89 QuicAckListenerInterface* ack_notifier_delegate) { | |
| 90 WriteOrBufferData(data, fin, ack_notifier_delegate); | |
| 91 } | |
| 92 | |
| 93 size_t QuicSpdyStream::WriteTrailers( | |
| 94 SpdyHeaderBlock trailer_block, | |
| 95 QuicAckListenerInterface* ack_notifier_delegate) { | |
| 96 if (fin_sent()) { | |
| 97 QUIC_BUG << "Trailers cannot be sent after a FIN."; | |
| 98 return 0; | |
| 99 } | |
| 100 | |
| 101 // The header block must contain the final offset for this stream, as the | |
| 102 // trailers may be processed out of order at the peer. | |
| 103 DVLOG(1) << "Inserting trailer: (" << kFinalOffsetHeaderKey << ", " | |
| 104 << stream_bytes_written() + queued_data_bytes() << ")"; | |
| 105 trailer_block.insert(std::make_pair( | |
| 106 kFinalOffsetHeaderKey, | |
| 107 IntToString(stream_bytes_written() + queued_data_bytes()))); | |
| 108 | |
| 109 // Write the trailing headers with a FIN, and close stream for writing: | |
| 110 // trailers are the last thing to be sent on a stream. | |
| 111 const bool kFin = true; | |
| 112 size_t bytes_written = spdy_session_->WriteHeaders( | |
| 113 id(), std::move(trailer_block), kFin, priority_, ack_notifier_delegate); | |
| 114 set_fin_sent(kFin); | |
| 115 | |
| 116 // Trailers are the last thing to be sent on a stream, but if there is still | |
| 117 // queued data then CloseWriteSide() will cause it never to be sent. | |
| 118 if (queued_data_bytes() == 0) { | |
| 119 CloseWriteSide(); | |
| 120 } | |
| 121 | |
| 122 return bytes_written; | |
| 123 } | |
| 124 | |
| 125 size_t QuicSpdyStream::Readv(const struct iovec* iov, size_t iov_len) { | |
| 126 DCHECK(FinishedReadingHeaders()); | |
| 127 return sequencer()->Readv(iov, iov_len); | |
| 128 } | |
| 129 | |
| 130 int QuicSpdyStream::GetReadableRegions(iovec* iov, size_t iov_len) const { | |
| 131 DCHECK(FinishedReadingHeaders()); | |
| 132 return sequencer()->GetReadableRegions(iov, iov_len); | |
| 133 } | |
| 134 | |
| 135 void QuicSpdyStream::MarkConsumed(size_t num_bytes) { | |
| 136 DCHECK(FinishedReadingHeaders()); | |
| 137 return sequencer()->MarkConsumed(num_bytes); | |
| 138 } | |
| 139 | |
| 140 bool QuicSpdyStream::IsDoneReading() const { | |
| 141 bool done_reading_headers = FinishedReadingHeaders(); | |
| 142 bool done_reading_body = sequencer()->IsClosed(); | |
| 143 bool done_reading_trailers = FinishedReadingTrailers(); | |
| 144 return done_reading_headers && done_reading_body && done_reading_trailers; | |
| 145 } | |
| 146 | |
| 147 bool QuicSpdyStream::HasBytesToRead() const { | |
| 148 bool headers_to_read = !decompressed_headers_.empty(); | |
| 149 bool body_to_read = sequencer()->HasBytesToRead(); | |
| 150 bool trailers_to_read = !decompressed_trailers_.empty(); | |
| 151 return headers_to_read || body_to_read || trailers_to_read; | |
| 152 } | |
| 153 | |
| 154 void QuicSpdyStream::MarkHeadersConsumed(size_t bytes_consumed) { | |
| 155 decompressed_headers_.erase(0, bytes_consumed); | |
| 156 if (FinishedReadingHeaders()) { | |
| 157 sequencer()->SetUnblocked(); | |
| 158 } | |
| 159 } | |
| 160 | |
| 161 void QuicSpdyStream::MarkTrailersConsumed(size_t bytes_consumed) { | |
| 162 decompressed_trailers_.erase(0, bytes_consumed); | |
| 163 } | |
| 164 | |
| 165 void QuicSpdyStream::MarkTrailersDelivered() { | |
| 166 trailers_delivered_ = true; | |
| 167 } | |
| 168 | |
| 169 void QuicSpdyStream::ConsumeHeaderList() { | |
| 170 header_list_.Clear(); | |
| 171 if (FinishedReadingHeaders()) { | |
| 172 sequencer()->SetUnblocked(); | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 void QuicSpdyStream::SetPriority(SpdyPriority priority) { | |
| 177 DCHECK_EQ(0u, stream_bytes_written()); | |
| 178 spdy_session_->UpdateStreamPriority(id(), priority); | |
| 179 priority_ = priority; | |
| 180 } | |
| 181 | |
| 182 void QuicSpdyStream::OnStreamHeaders(StringPiece headers_data) { | |
| 183 if (!headers_decompressed_) { | |
| 184 headers_data.AppendToString(&decompressed_headers_); | |
| 185 } else { | |
| 186 DCHECK(!trailers_decompressed_); | |
| 187 headers_data.AppendToString(&decompressed_trailers_); | |
| 188 } | |
| 189 } | |
| 190 | |
| 191 void QuicSpdyStream::OnStreamHeadersPriority(SpdyPriority priority) { | |
| 192 DCHECK_EQ(Perspective::IS_SERVER, session()->connection()->perspective()); | |
| 193 SetPriority(priority); | |
| 194 } | |
| 195 | |
| 196 void QuicSpdyStream::OnStreamHeadersComplete(bool fin, size_t frame_len) { | |
| 197 if (!headers_decompressed_) { | |
| 198 OnInitialHeadersComplete(fin, frame_len); | |
| 199 } else { | |
| 200 OnTrailingHeadersComplete(fin, frame_len); | |
| 201 } | |
| 202 } | |
| 203 | |
| 204 void QuicSpdyStream::OnStreamHeaderList(bool fin, | |
| 205 size_t frame_len, | |
| 206 const QuicHeaderList& header_list) { | |
| 207 if (!headers_decompressed_) { | |
| 208 OnInitialHeadersComplete(fin, frame_len, header_list); | |
| 209 } else { | |
| 210 OnTrailingHeadersComplete(fin, frame_len, header_list); | |
| 211 } | |
| 212 } | |
| 213 | |
| 214 void QuicSpdyStream::OnInitialHeadersComplete(bool fin, size_t /*frame_len*/) { | |
| 215 headers_decompressed_ = true; | |
| 216 if (fin) { | |
| 217 OnStreamFrame(QuicStreamFrame(id(), fin, 0, StringPiece())); | |
| 218 } | |
| 219 if (FinishedReadingHeaders()) { | |
| 220 sequencer()->SetUnblocked(); | |
| 221 } | |
| 222 } | |
| 223 | |
| 224 void QuicSpdyStream::OnInitialHeadersComplete( | |
| 225 bool fin, | |
| 226 size_t /*frame_len*/, | |
| 227 const QuicHeaderList& header_list) { | |
| 228 headers_decompressed_ = true; | |
| 229 header_list_ = header_list; | |
| 230 if (fin) { | |
| 231 OnStreamFrame(QuicStreamFrame(id(), fin, 0, StringPiece())); | |
| 232 } | |
| 233 if (FinishedReadingHeaders()) { | |
| 234 sequencer()->SetUnblocked(); | |
| 235 } | |
| 236 } | |
| 237 | |
| 238 void QuicSpdyStream::OnPromiseHeaders(StringPiece headers_data) { | |
| 239 headers_data.AppendToString(&decompressed_headers_); | |
| 240 } | |
| 241 | |
| 242 void QuicSpdyStream::OnPromiseHeadersComplete( | |
| 243 QuicStreamId /* promised_stream_id */, | |
| 244 size_t /* frame_len */) { | |
| 245 // To be overridden in QuicSpdyClientStream. Not supported on | |
| 246 // server side. | |
| 247 session()->connection()->CloseConnection( | |
| 248 QUIC_INVALID_HEADERS_STREAM_DATA, "Promise headers received by server", | |
| 249 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); | |
| 250 return; | |
| 251 } | |
| 252 | |
| 253 void QuicSpdyStream::OnPromiseHeaderList( | |
| 254 QuicStreamId /* promised_id */, | |
| 255 size_t /* frame_len */, | |
| 256 const QuicHeaderList& /*header_list */) { | |
| 257 // To be overridden in QuicSpdyClientStream. Not supported on | |
| 258 // server side. | |
| 259 session()->connection()->CloseConnection( | |
| 260 QUIC_INVALID_HEADERS_STREAM_DATA, "Promise headers received by server", | |
| 261 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); | |
| 262 return; | |
| 263 } | |
| 264 | |
| 265 void QuicSpdyStream::OnTrailingHeadersComplete(bool fin, size_t /*frame_len*/) { | |
| 266 DCHECK(!trailers_decompressed_); | |
| 267 if (fin_received()) { | |
| 268 DLOG(ERROR) << "Received Trailers after FIN, on stream: " << id(); | |
| 269 session()->connection()->CloseConnection( | |
| 270 QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers after fin", | |
| 271 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); | |
| 272 return; | |
| 273 } | |
| 274 if (!fin) { | |
| 275 DLOG(ERROR) << "Trailers must have FIN set, on stream: " << id(); | |
| 276 session()->connection()->CloseConnection( | |
| 277 QUIC_INVALID_HEADERS_STREAM_DATA, "Fin missing from trailers", | |
| 278 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); | |
| 279 return; | |
| 280 } | |
| 281 | |
| 282 size_t final_byte_offset = 0; | |
| 283 if (!SpdyUtils::ParseTrailers(decompressed_trailers().data(), | |
| 284 decompressed_trailers().length(), | |
| 285 &final_byte_offset, &received_trailers_)) { | |
| 286 DLOG(ERROR) << "Trailers are malformed: " << id(); | |
| 287 session()->connection()->CloseConnection( | |
| 288 QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers are malformed", | |
| 289 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); | |
| 290 return; | |
| 291 } | |
| 292 | |
| 293 // The data on this stream ends at |final_byte_offset|. | |
| 294 DVLOG(1) << "Stream ends at byte offset: " << final_byte_offset | |
| 295 << " currently read: " << stream_bytes_read(); | |
| 296 | |
| 297 OnStreamFrame(QuicStreamFrame(id(), fin, final_byte_offset, StringPiece())); | |
| 298 trailers_decompressed_ = true; | |
| 299 } | |
| 300 | |
| 301 void QuicSpdyStream::OnTrailingHeadersComplete( | |
| 302 bool fin, | |
| 303 size_t /*frame_len*/, | |
| 304 const QuicHeaderList& header_list) { | |
| 305 DCHECK(!trailers_decompressed_); | |
| 306 if (fin_received()) { | |
| 307 DLOG(ERROR) << "Received Trailers after FIN, on stream: " << id(); | |
| 308 session()->connection()->CloseConnection( | |
| 309 QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers after fin", | |
| 310 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); | |
| 311 return; | |
| 312 } | |
| 313 if (!fin) { | |
| 314 DLOG(ERROR) << "Trailers must have FIN set, on stream: " << id(); | |
| 315 session()->connection()->CloseConnection( | |
| 316 QUIC_INVALID_HEADERS_STREAM_DATA, "Fin missing from trailers", | |
| 317 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); | |
| 318 return; | |
| 319 } | |
| 320 | |
| 321 size_t final_byte_offset = 0; | |
| 322 if (!SpdyUtils::CopyAndValidateTrailers(header_list, &final_byte_offset, | |
| 323 &received_trailers_)) { | |
| 324 DLOG(ERROR) << "Trailers are malformed: " << id(); | |
| 325 session()->connection()->CloseConnection( | |
| 326 QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers are malformed", | |
| 327 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); | |
| 328 return; | |
| 329 } | |
| 330 OnStreamFrame(QuicStreamFrame(id(), fin, final_byte_offset, StringPiece())); | |
| 331 trailers_decompressed_ = true; | |
| 332 } | |
| 333 | |
| 334 void QuicSpdyStream::OnStreamReset(const QuicRstStreamFrame& frame) { | |
| 335 if (frame.error_code != QUIC_STREAM_NO_ERROR) { | |
| 336 ReliableQuicStream::OnStreamReset(frame); | |
| 337 return; | |
| 338 } | |
| 339 DVLOG(1) << "Received QUIC_STREAM_NO_ERROR, not discarding response"; | |
| 340 set_rst_received(true); | |
| 341 MaybeIncreaseHighestReceivedOffset(frame.byte_offset); | |
| 342 set_stream_error(frame.error_code); | |
| 343 CloseWriteSide(); | |
| 344 } | |
| 345 | |
| 346 void QuicSpdyStream::OnClose() { | |
| 347 ReliableQuicStream::OnClose(); | |
| 348 | |
| 349 if (visitor_) { | |
| 350 Visitor* visitor = visitor_; | |
| 351 // Calling Visitor::OnClose() may result the destruction of the visitor, | |
| 352 // so we need to ensure we don't call it again. | |
| 353 visitor_ = nullptr; | |
| 354 visitor->OnClose(this); | |
| 355 } | |
| 356 } | |
| 357 | |
| 358 bool QuicSpdyStream::FinishedReadingHeaders() const { | |
| 359 return headers_decompressed_ && decompressed_headers_.empty() && | |
| 360 header_list_.empty(); | |
| 361 } | |
| 362 | |
| 363 bool QuicSpdyStream::ParseHeaderStatusCode(const SpdyHeaderBlock& header, | |
| 364 int* status_code) const { | |
| 365 SpdyHeaderBlock::const_iterator it = header.find(":status"); | |
| 366 if (it == header.end()) { | |
| 367 return false; | |
| 368 } | |
| 369 const StringPiece status(it->second); | |
| 370 if (status.size() != 3) { | |
| 371 return false; | |
| 372 } | |
| 373 // First character must be an integer in range [1,5]. | |
| 374 if (status[0] < '1' || status[0] > '5') { | |
| 375 return false; | |
| 376 } | |
| 377 // The remaining two characters must be integers. | |
| 378 if (!isdigit(status[1]) || !isdigit(status[2])) { | |
| 379 return false; | |
| 380 } | |
| 381 return StringToInt(status, status_code); | |
| 382 } | |
| 383 | |
| 384 bool QuicSpdyStream::FinishedReadingTrailers() const { | |
| 385 // If no further trailing headers are expected, and the decompressed trailers | |
| 386 // (if any) have been consumed, then reading of trailers is finished. | |
| 387 if (!fin_received()) { | |
| 388 return false; | |
| 389 } else if (!trailers_decompressed_) { | |
| 390 return true; | |
| 391 } else { | |
| 392 return trailers_delivered_ && decompressed_trailers_.empty(); | |
| 393 } | |
| 394 } | |
| 395 | |
| 396 SpdyPriority QuicSpdyStream::priority() const { | |
| 397 return priority_; | |
| 398 } | |
| 399 | |
| 400 void QuicSpdyStream::ClearSession() { | |
| 401 spdy_session_ = nullptr; | |
| 402 } | |
| 403 | |
| 404 QuicConsumedData QuicSpdyStream::WritevDataInner( | |
| 405 QuicIOVector iov, | |
| 406 QuicStreamOffset offset, | |
| 407 bool fin, | |
| 408 QuicAckListenerInterface* ack_notifier_delegate) { | |
| 409 if (spdy_session_->headers_stream() != nullptr && | |
| 410 spdy_session_->force_hol_blocking()) { | |
| 411 return spdy_session_->headers_stream()->WritevStreamData( | |
| 412 id(), iov, offset, fin, ack_notifier_delegate); | |
| 413 } | |
| 414 return ReliableQuicStream::WritevDataInner(iov, offset, fin, | |
| 415 ack_notifier_delegate); | |
| 416 } | |
| 417 | |
| 418 } // namespace net | |
| OLD | NEW |