QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 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/third_party/quiche/src/quic/core/http/quic_spdy_stream.h" |
| 6 | |
| 7 | #include <utility> |
| 8 | |
| 9 | #include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h" |
| 10 | #include "net/third_party/quiche/src/quic/core/http/spdy_utils.h" |
| 11 | #include "net/third_party/quiche/src/quic/core/quic_utils.h" |
| 12 | #include "net/third_party/quiche/src/quic/core/quic_write_blocked_list.h" |
| 13 | #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" |
| 14 | #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" |
| 15 | #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" |
| 16 | #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" |
| 17 | #include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h" |
| 18 | #include "net/third_party/quiche/src/quic/platform/api/quic_string.h" |
| 19 | #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" |
| 20 | #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" |
| 21 | #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" |
| 22 | |
| 23 | using spdy::SpdyHeaderBlock; |
| 24 | using spdy::SpdyPriority; |
| 25 | |
| 26 | namespace quic { |
| 27 | |
| 28 | // Visitor of HttpDecoder that passes data frame to QuicSpdyStream and closes |
| 29 | // the connection on unexpected frames. |
| 30 | class QuicSpdyStream::HttpDecoderVisitor : public HttpDecoder::Visitor { |
| 31 | public: |
| 32 | explicit HttpDecoderVisitor(QuicSpdyStream* stream) : stream_(stream) {} |
| 33 | HttpDecoderVisitor(const HttpDecoderVisitor&) = delete; |
| 34 | HttpDecoderVisitor& operator=(const HttpDecoderVisitor&) = delete; |
| 35 | |
| 36 | void OnError(HttpDecoder* decoder) override { |
| 37 | stream_->session()->connection()->CloseConnection( |
| 38 | QUIC_HTTP_DECODER_ERROR, "Http decoder internal error", |
| 39 | ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); |
| 40 | } |
| 41 | |
| 42 | void OnPriorityFrame(const PriorityFrame& frame) override { |
| 43 | CloseConnectionOnWrongFrame("Priority"); |
| 44 | } |
| 45 | |
| 46 | void OnCancelPushFrame(const CancelPushFrame& frame) override { |
| 47 | CloseConnectionOnWrongFrame("Cancel Push"); |
| 48 | } |
| 49 | |
| 50 | void OnMaxPushIdFrame(const MaxPushIdFrame& frame) override { |
| 51 | CloseConnectionOnWrongFrame("Max Push Id"); |
| 52 | } |
| 53 | |
| 54 | void OnGoAwayFrame(const GoAwayFrame& frame) override { |
| 55 | CloseConnectionOnWrongFrame("Goaway"); |
| 56 | } |
| 57 | |
| 58 | void OnSettingsFrame(const SettingsFrame& frame) override { |
| 59 | CloseConnectionOnWrongFrame("Settings"); |
| 60 | } |
| 61 | |
| 62 | void OnDuplicatePushFrame(const DuplicatePushFrame& frame) override { |
| 63 | CloseConnectionOnWrongFrame("Duplicate Push"); |
| 64 | } |
| 65 | |
| 66 | void OnDataFrameStart(Http3FrameLengths frame_lengths) override { |
| 67 | stream_->OnDataFrameStart(frame_lengths); |
| 68 | } |
| 69 | |
| 70 | void OnDataFramePayload(QuicStringPiece payload) override { |
| 71 | stream_->OnDataFramePayload(payload); |
| 72 | } |
| 73 | |
| 74 | void OnDataFrameEnd() override { stream_->OnDataFrameEnd(); } |
| 75 | |
| 76 | void OnHeadersFrameStart() override { |
| 77 | CloseConnectionOnWrongFrame("Headers"); |
| 78 | } |
| 79 | |
| 80 | void OnHeadersFramePayload(QuicStringPiece payload) override { |
| 81 | CloseConnectionOnWrongFrame("Headers"); |
| 82 | } |
| 83 | |
| 84 | void OnHeadersFrameEnd(QuicByteCount frame_len) override { |
| 85 | CloseConnectionOnWrongFrame("Headers"); |
| 86 | } |
| 87 | |
| 88 | void OnPushPromiseFrameStart(PushId push_id) override { |
| 89 | CloseConnectionOnWrongFrame("Push Promise"); |
| 90 | } |
| 91 | |
| 92 | void OnPushPromiseFramePayload(QuicStringPiece payload) override { |
| 93 | CloseConnectionOnWrongFrame("Push Promise"); |
| 94 | } |
| 95 | |
| 96 | void OnPushPromiseFrameEnd() override { |
| 97 | CloseConnectionOnWrongFrame("Push Promise"); |
| 98 | } |
| 99 | |
| 100 | private: |
| 101 | void CloseConnectionOnWrongFrame(QuicString frame_type) { |
| 102 | stream_->session()->connection()->CloseConnection( |
| 103 | QUIC_HTTP_DECODER_ERROR, frame_type + " frame received on data stream", |
| 104 | ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); |
| 105 | } |
| 106 | |
| 107 | QuicSpdyStream* stream_; |
| 108 | }; |
| 109 | |
| 110 | #define ENDPOINT \ |
| 111 | (session()->perspective() == Perspective::IS_SERVER ? "Server: " \ |
| 112 | : "Client:" \ |
| 113 | " ") |
| 114 | |
| 115 | QuicSpdyStream::QuicSpdyStream(QuicStreamId id, |
| 116 | QuicSpdySession* spdy_session, |
| 117 | StreamType type) |
| 118 | : QuicStream(id, spdy_session, /*is_static=*/false, type), |
| 119 | spdy_session_(spdy_session), |
| 120 | visitor_(nullptr), |
| 121 | headers_decompressed_(false), |
| 122 | trailers_decompressed_(false), |
| 123 | trailers_consumed_(false), |
| 124 | http_decoder_visitor_(new HttpDecoderVisitor(this)), |
| 125 | body_buffer_(sequencer()), |
| 126 | ack_listener_(nullptr) { |
| 127 | DCHECK_NE(QuicUtils::GetCryptoStreamId( |
| 128 | spdy_session->connection()->transport_version()), |
| 129 | id); |
| 130 | // Don't receive any callbacks from the sequencer until headers |
| 131 | // are complete. |
| 132 | sequencer()->SetBlockedUntilFlush(); |
| 133 | |
| 134 | if (VersionHasDataFrameHeader( |
| 135 | spdy_session_->connection()->transport_version())) { |
| 136 | sequencer()->set_level_triggered(true); |
| 137 | } |
| 138 | decoder_.set_visitor(http_decoder_visitor_.get()); |
| 139 | } |
| 140 | |
| 141 | QuicSpdyStream::QuicSpdyStream(PendingStream pending, |
| 142 | QuicSpdySession* spdy_session, |
| 143 | StreamType type) |
| 144 | : QuicStream(std::move(pending), type), |
| 145 | spdy_session_(spdy_session), |
| 146 | visitor_(nullptr), |
| 147 | headers_decompressed_(false), |
| 148 | trailers_decompressed_(false), |
| 149 | trailers_consumed_(false), |
| 150 | http_decoder_visitor_(new HttpDecoderVisitor(this)), |
| 151 | body_buffer_(sequencer()), |
| 152 | ack_listener_(nullptr) { |
| 153 | DCHECK_NE(QuicUtils::GetCryptoStreamId( |
| 154 | spdy_session->connection()->transport_version()), |
| 155 | id()); |
| 156 | // Don't receive any callbacks from the sequencer until headers |
| 157 | // are complete. |
| 158 | sequencer()->SetBlockedUntilFlush(); |
| 159 | |
| 160 | if (VersionHasDataFrameHeader( |
| 161 | spdy_session_->connection()->transport_version())) { |
| 162 | sequencer()->set_level_triggered(true); |
| 163 | } |
| 164 | decoder_.set_visitor(http_decoder_visitor_.get()); |
| 165 | } |
| 166 | |
| 167 | QuicSpdyStream::~QuicSpdyStream() {} |
| 168 | |
| 169 | size_t QuicSpdyStream::WriteHeaders( |
| 170 | SpdyHeaderBlock header_block, |
| 171 | bool fin, |
| 172 | QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { |
| 173 | size_t bytes_written = |
| 174 | WriteHeadersImpl(std::move(header_block), fin, std::move(ack_listener)); |
| 175 | if (fin) { |
| 176 | // TODO(rch): Add test to ensure fin_sent_ is set whenever a fin is sent. |
| 177 | set_fin_sent(true); |
| 178 | CloseWriteSide(); |
| 179 | } |
| 180 | return bytes_written; |
| 181 | } |
| 182 | |
| 183 | void QuicSpdyStream::WriteOrBufferBody(QuicStringPiece data, bool fin) { |
| 184 | if (!VersionHasDataFrameHeader( |
| 185 | spdy_session_->connection()->transport_version()) || |
| 186 | data.length() == 0) { |
| 187 | WriteOrBufferData(data, fin, nullptr); |
| 188 | return; |
| 189 | } |
| 190 | QuicConnection::ScopedPacketFlusher flusher( |
| 191 | spdy_session_->connection(), QuicConnection::SEND_ACK_IF_PENDING); |
| 192 | |
| 193 | // Write frame header. |
| 194 | std::unique_ptr<char[]> buffer; |
| 195 | QuicByteCount header_length = |
| 196 | encoder_.SerializeDataFrameHeader(data.length(), &buffer); |
| 197 | unacked_frame_headers_offsets_.Add( |
| 198 | send_buffer().stream_offset(), |
| 199 | send_buffer().stream_offset() + header_length); |
| 200 | QUIC_DLOG(INFO) << "Stream " << id() << " is writing header of length " |
| 201 | << header_length; |
| 202 | WriteOrBufferData(QuicStringPiece(buffer.get(), header_length), false, |
| 203 | nullptr); |
| 204 | |
| 205 | // Write body. |
| 206 | QUIC_DLOG(INFO) << "Stream " << id() << " is writing body of length " |
| 207 | << data.length(); |
| 208 | WriteOrBufferData(data, fin, nullptr); |
| 209 | } |
| 210 | |
| 211 | size_t QuicSpdyStream::WriteTrailers( |
| 212 | SpdyHeaderBlock trailer_block, |
| 213 | QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { |
| 214 | if (fin_sent()) { |
| 215 | QUIC_BUG << "Trailers cannot be sent after a FIN, on stream " << id(); |
| 216 | return 0; |
| 217 | } |
| 218 | |
| 219 | // The header block must contain the final offset for this stream, as the |
| 220 | // trailers may be processed out of order at the peer. |
| 221 | QUIC_DLOG(INFO) << "Inserting trailer: (" << kFinalOffsetHeaderKey << ", " |
| 222 | << stream_bytes_written() + BufferedDataBytes() << ")"; |
| 223 | trailer_block.insert( |
| 224 | std::make_pair(kFinalOffsetHeaderKey, |
| 225 | QuicTextUtils::Uint64ToString(stream_bytes_written() + |
| 226 | BufferedDataBytes()))); |
| 227 | |
| 228 | // Write the trailing headers with a FIN, and close stream for writing: |
| 229 | // trailers are the last thing to be sent on a stream. |
| 230 | const bool kFin = true; |
| 231 | size_t bytes_written = |
| 232 | WriteHeadersImpl(std::move(trailer_block), kFin, std::move(ack_listener)); |
| 233 | set_fin_sent(kFin); |
| 234 | |
| 235 | // Trailers are the last thing to be sent on a stream, but if there is still |
| 236 | // queued data then CloseWriteSide() will cause it never to be sent. |
| 237 | if (BufferedDataBytes() == 0) { |
| 238 | CloseWriteSide(); |
| 239 | } |
| 240 | |
| 241 | return bytes_written; |
| 242 | } |
| 243 | |
| 244 | QuicConsumedData QuicSpdyStream::WritevBody(const struct iovec* iov, |
| 245 | int count, |
| 246 | bool fin) { |
| 247 | if (!GetQuicReloadableFlag(quic_call_write_mem_slices)) { |
| 248 | return WritevData(iov, count, fin); |
| 249 | } |
| 250 | QUIC_RELOADABLE_FLAG_COUNT(quic_call_write_mem_slices); |
| 251 | QuicMemSliceStorage storage( |
| 252 | iov, count, |
| 253 | session()->connection()->helper()->GetStreamSendBufferAllocator(), |
| 254 | GetQuicFlag(FLAGS_quic_send_buffer_max_data_slice_size)); |
| 255 | return WriteBodySlices(storage.ToSpan(), fin); |
| 256 | } |
| 257 | |
| 258 | QuicConsumedData QuicSpdyStream::WriteBodySlices(QuicMemSliceSpan slices, |
| 259 | bool fin) { |
| 260 | if (!VersionHasDataFrameHeader( |
| 261 | spdy_session_->connection()->transport_version()) || |
| 262 | slices.empty()) { |
| 263 | return WriteMemSlices(slices, fin); |
| 264 | } |
| 265 | |
| 266 | std::unique_ptr<char[]> buffer; |
| 267 | QuicByteCount header_length = |
| 268 | encoder_.SerializeDataFrameHeader(slices.total_length(), &buffer); |
| 269 | if (!CanWriteNewDataAfterData(header_length)) { |
| 270 | return {0, false}; |
| 271 | } |
| 272 | |
| 273 | QuicConnection::ScopedPacketFlusher flusher( |
| 274 | spdy_session_->connection(), QuicConnection::SEND_ACK_IF_PENDING); |
| 275 | |
| 276 | // Write frame header. |
| 277 | struct iovec header_iov = {static_cast<void*>(buffer.get()), header_length}; |
| 278 | QuicMemSliceStorage storage( |
| 279 | &header_iov, 1, |
| 280 | spdy_session_->connection()->helper()->GetStreamSendBufferAllocator(), |
| 281 | GetQuicFlag(FLAGS_quic_send_buffer_max_data_slice_size)); |
| 282 | unacked_frame_headers_offsets_.Add( |
| 283 | send_buffer().stream_offset(), |
| 284 | send_buffer().stream_offset() + header_length); |
| 285 | QUIC_DLOG(INFO) << "Stream " << id() << " is writing header of length " |
| 286 | << header_length; |
| 287 | WriteMemSlices(storage.ToSpan(), false); |
| 288 | |
| 289 | // Write body. |
| 290 | QUIC_DLOG(INFO) << "Stream " << id() << " is writing body of length " |
| 291 | << slices.total_length(); |
| 292 | return WriteMemSlices(slices, fin); |
| 293 | } |
| 294 | |
| 295 | size_t QuicSpdyStream::Readv(const struct iovec* iov, size_t iov_len) { |
| 296 | DCHECK(FinishedReadingHeaders()); |
| 297 | if (!VersionHasDataFrameHeader( |
| 298 | spdy_session_->connection()->transport_version())) { |
| 299 | return sequencer()->Readv(iov, iov_len); |
| 300 | } |
| 301 | return body_buffer_.ReadBody(iov, iov_len); |
| 302 | } |
| 303 | |
| 304 | int QuicSpdyStream::GetReadableRegions(iovec* iov, size_t iov_len) const { |
| 305 | DCHECK(FinishedReadingHeaders()); |
| 306 | if (!VersionHasDataFrameHeader( |
| 307 | spdy_session_->connection()->transport_version())) { |
| 308 | return sequencer()->GetReadableRegions(iov, iov_len); |
| 309 | } |
| 310 | return body_buffer_.PeekBody(iov, iov_len); |
| 311 | } |
| 312 | |
| 313 | void QuicSpdyStream::MarkConsumed(size_t num_bytes) { |
| 314 | DCHECK(FinishedReadingHeaders()); |
| 315 | if (!VersionHasDataFrameHeader( |
| 316 | spdy_session_->connection()->transport_version())) { |
| 317 | sequencer()->MarkConsumed(num_bytes); |
| 318 | return; |
| 319 | } |
| 320 | body_buffer_.MarkBodyConsumed(num_bytes); |
| 321 | } |
| 322 | |
| 323 | bool QuicSpdyStream::IsDoneReading() const { |
| 324 | bool done_reading_headers = FinishedReadingHeaders(); |
| 325 | bool done_reading_body = sequencer()->IsClosed(); |
| 326 | bool done_reading_trailers = FinishedReadingTrailers(); |
| 327 | return done_reading_headers && done_reading_body && done_reading_trailers; |
| 328 | } |
| 329 | |
| 330 | bool QuicSpdyStream::HasBytesToRead() const { |
| 331 | if (!VersionHasDataFrameHeader( |
| 332 | spdy_session_->connection()->transport_version())) { |
| 333 | return sequencer()->HasBytesToRead(); |
| 334 | } |
| 335 | return body_buffer_.HasBytesToRead(); |
| 336 | } |
| 337 | |
| 338 | void QuicSpdyStream::MarkTrailersConsumed() { |
| 339 | trailers_consumed_ = true; |
| 340 | } |
| 341 | |
| 342 | uint64_t QuicSpdyStream::total_body_bytes_read() const { |
| 343 | if (VersionHasDataFrameHeader( |
| 344 | spdy_session_->connection()->transport_version())) { |
| 345 | return body_buffer_.total_body_bytes_received(); |
| 346 | } |
| 347 | return sequencer()->NumBytesConsumed(); |
| 348 | } |
| 349 | |
| 350 | void QuicSpdyStream::ConsumeHeaderList() { |
| 351 | header_list_.Clear(); |
| 352 | if (FinishedReadingHeaders()) { |
| 353 | sequencer()->SetUnblocked(); |
| 354 | } |
| 355 | } |
| 356 | |
| 357 | void QuicSpdyStream::OnStreamHeadersPriority(SpdyPriority priority) { |
| 358 | DCHECK_EQ(Perspective::IS_SERVER, session()->connection()->perspective()); |
| 359 | SetPriority(priority); |
| 360 | } |
| 361 | |
| 362 | void QuicSpdyStream::OnStreamHeaderList(bool fin, |
| 363 | size_t frame_len, |
| 364 | const QuicHeaderList& header_list) { |
| 365 | // The headers list avoid infinite buffering by clearing the headers list |
| 366 | // if the current headers are too large. So if the list is empty here |
| 367 | // then the headers list must have been too large, and the stream should |
| 368 | // be reset. |
| 369 | // TODO(rch): Use an explicit "headers too large" signal. An empty header list |
| 370 | // might be acceptable if it corresponds to a trailing header frame. |
| 371 | if (header_list.empty()) { |
| 372 | OnHeadersTooLarge(); |
| 373 | if (IsDoneReading()) { |
| 374 | return; |
| 375 | } |
| 376 | } |
| 377 | if (!headers_decompressed_) { |
| 378 | OnInitialHeadersComplete(fin, frame_len, header_list); |
| 379 | } else { |
| 380 | OnTrailingHeadersComplete(fin, frame_len, header_list); |
| 381 | } |
| 382 | } |
| 383 | |
| 384 | void QuicSpdyStream::OnHeadersTooLarge() { |
| 385 | Reset(QUIC_HEADERS_TOO_LARGE); |
| 386 | } |
| 387 | |
| 388 | void QuicSpdyStream::OnInitialHeadersComplete( |
| 389 | bool fin, |
| 390 | size_t /*frame_len*/, |
| 391 | const QuicHeaderList& header_list) { |
| 392 | headers_decompressed_ = true; |
| 393 | header_list_ = header_list; |
| 394 | if (fin) { |
| 395 | OnStreamFrame(QuicStreamFrame(id(), fin, 0, QuicStringPiece())); |
| 396 | } |
| 397 | if (FinishedReadingHeaders()) { |
| 398 | sequencer()->SetUnblocked(); |
| 399 | } |
| 400 | } |
| 401 | |
| 402 | void QuicSpdyStream::OnPromiseHeaderList( |
| 403 | QuicStreamId /* promised_id */, |
| 404 | size_t /* frame_len */, |
| 405 | const QuicHeaderList& /*header_list */) { |
| 406 | // To be overridden in QuicSpdyClientStream. Not supported on |
| 407 | // server side. |
| 408 | session()->connection()->CloseConnection( |
| 409 | QUIC_INVALID_HEADERS_STREAM_DATA, "Promise headers received by server", |
| 410 | ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); |
| 411 | } |
| 412 | |
| 413 | void QuicSpdyStream::OnTrailingHeadersComplete( |
| 414 | bool fin, |
| 415 | size_t /*frame_len*/, |
| 416 | const QuicHeaderList& header_list) { |
| 417 | DCHECK(!trailers_decompressed_); |
| 418 | if (fin_received()) { |
| 419 | QUIC_DLOG(ERROR) << "Received Trailers after FIN, on stream: " << id(); |
| 420 | session()->connection()->CloseConnection( |
| 421 | QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers after fin", |
| 422 | ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); |
| 423 | return; |
| 424 | } |
| 425 | if (!fin) { |
| 426 | QUIC_DLOG(ERROR) << "Trailers must have FIN set, on stream: " << id(); |
| 427 | session()->connection()->CloseConnection( |
| 428 | QUIC_INVALID_HEADERS_STREAM_DATA, "Fin missing from trailers", |
| 429 | ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); |
| 430 | return; |
| 431 | } |
| 432 | |
| 433 | size_t final_byte_offset = 0; |
| 434 | if (!SpdyUtils::CopyAndValidateTrailers(header_list, &final_byte_offset, |
| 435 | &received_trailers_)) { |
| 436 | QUIC_DLOG(ERROR) << "Trailers for stream " << id() << " are malformed."; |
| 437 | session()->connection()->CloseConnection( |
| 438 | QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers are malformed", |
| 439 | ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); |
| 440 | return; |
| 441 | } |
| 442 | trailers_decompressed_ = true; |
| 443 | OnStreamFrame( |
| 444 | QuicStreamFrame(id(), fin, final_byte_offset, QuicStringPiece())); |
| 445 | } |
| 446 | |
| 447 | size_t QuicSpdyStream::WriteHeadersImpl( |
| 448 | spdy::SpdyHeaderBlock header_block, |
| 449 | bool fin, |
| 450 | QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { |
| 451 | return spdy_session_->WriteHeadersOnHeadersStream( |
| 452 | id(), std::move(header_block), fin, priority(), std::move(ack_listener)); |
| 453 | } |
| 454 | |
| 455 | void QuicSpdyStream::OnPriorityFrame(SpdyPriority priority) { |
| 456 | DCHECK_EQ(Perspective::IS_SERVER, session()->connection()->perspective()); |
| 457 | SetPriority(priority); |
| 458 | } |
| 459 | |
| 460 | void QuicSpdyStream::OnStreamReset(const QuicRstStreamFrame& frame) { |
| 461 | if (frame.error_code != QUIC_STREAM_NO_ERROR) { |
| 462 | QuicStream::OnStreamReset(frame); |
| 463 | return; |
| 464 | } |
| 465 | QUIC_DVLOG(1) << "Received QUIC_STREAM_NO_ERROR, not discarding response"; |
| 466 | set_rst_received(true); |
| 467 | MaybeIncreaseHighestReceivedOffset(frame.byte_offset); |
| 468 | set_stream_error(frame.error_code); |
| 469 | CloseWriteSide(); |
| 470 | } |
| 471 | |
| 472 | void QuicSpdyStream::OnDataAvailable() { |
| 473 | if (!VersionHasDataFrameHeader( |
| 474 | session()->connection()->transport_version())) { |
| 475 | OnBodyAvailable(); |
| 476 | return; |
| 477 | } |
| 478 | |
| 479 | iovec iov; |
| 480 | bool has_payload = false; |
| 481 | while (sequencer()->PrefetchNextRegion(&iov)) { |
| 482 | decoder_.ProcessInput(reinterpret_cast<const char*>(iov.iov_base), |
| 483 | iov.iov_len); |
| 484 | if (decoder_.has_payload()) { |
| 485 | has_payload = true; |
| 486 | } |
| 487 | } |
| 488 | |
| 489 | if (has_payload) { |
| 490 | OnBodyAvailable(); |
| 491 | return; |
| 492 | } |
| 493 | |
| 494 | if (sequencer()->IsClosed()) { |
| 495 | OnBodyAvailable(); |
| 496 | return; |
| 497 | } |
| 498 | } |
| 499 | |
| 500 | void QuicSpdyStream::OnClose() { |
| 501 | QuicStream::OnClose(); |
| 502 | |
| 503 | if (visitor_) { |
| 504 | Visitor* visitor = visitor_; |
| 505 | // Calling Visitor::OnClose() may result the destruction of the visitor, |
| 506 | // so we need to ensure we don't call it again. |
| 507 | visitor_ = nullptr; |
| 508 | visitor->OnClose(this); |
| 509 | } |
| 510 | } |
| 511 | |
| 512 | void QuicSpdyStream::OnCanWrite() { |
| 513 | QuicStream::OnCanWrite(); |
| 514 | |
| 515 | // Trailers (and hence a FIN) may have been sent ahead of queued body bytes. |
| 516 | if (!HasBufferedData() && fin_sent()) { |
| 517 | CloseWriteSide(); |
| 518 | } |
| 519 | } |
| 520 | |
| 521 | bool QuicSpdyStream::FinishedReadingHeaders() const { |
| 522 | return headers_decompressed_ && header_list_.empty(); |
| 523 | } |
| 524 | |
| 525 | bool QuicSpdyStream::ParseHeaderStatusCode(const SpdyHeaderBlock& header, |
| 526 | int* status_code) const { |
| 527 | SpdyHeaderBlock::const_iterator it = header.find(spdy::kHttp2StatusHeader); |
| 528 | if (it == header.end()) { |
| 529 | return false; |
| 530 | } |
| 531 | const QuicStringPiece status(it->second); |
| 532 | if (status.size() != 3) { |
| 533 | return false; |
| 534 | } |
| 535 | // First character must be an integer in range [1,5]. |
| 536 | if (status[0] < '1' || status[0] > '5') { |
| 537 | return false; |
| 538 | } |
| 539 | // The remaining two characters must be integers. |
| 540 | if (!isdigit(status[1]) || !isdigit(status[2])) { |
| 541 | return false; |
| 542 | } |
| 543 | return QuicTextUtils::StringToInt(status, status_code); |
| 544 | } |
| 545 | |
| 546 | bool QuicSpdyStream::FinishedReadingTrailers() const { |
| 547 | // If no further trailing headers are expected, and the decompressed trailers |
| 548 | // (if any) have been consumed, then reading of trailers is finished. |
| 549 | if (!fin_received()) { |
| 550 | return false; |
| 551 | } else if (!trailers_decompressed_) { |
| 552 | return true; |
| 553 | } else { |
| 554 | return trailers_consumed_; |
| 555 | } |
| 556 | } |
| 557 | |
| 558 | void QuicSpdyStream::ClearSession() { |
| 559 | spdy_session_ = nullptr; |
| 560 | } |
| 561 | |
| 562 | void QuicSpdyStream::OnDataFrameStart(Http3FrameLengths frame_lengths) { |
| 563 | body_buffer_.OnDataHeader(frame_lengths); |
| 564 | } |
| 565 | |
| 566 | void QuicSpdyStream::OnDataFramePayload(QuicStringPiece payload) { |
| 567 | body_buffer_.OnDataPayload(payload); |
| 568 | } |
| 569 | |
| 570 | void QuicSpdyStream::OnDataFrameEnd() { |
| 571 | DVLOG(1) << "Reaches the end of a data frame. Total bytes received are " |
| 572 | << body_buffer_.total_body_bytes_received(); |
| 573 | } |
| 574 | |
| 575 | bool QuicSpdyStream::OnStreamFrameAcked(QuicStreamOffset offset, |
| 576 | QuicByteCount data_length, |
| 577 | bool fin_acked, |
| 578 | QuicTime::Delta ack_delay_time, |
| 579 | QuicByteCount* newly_acked_length) { |
| 580 | const bool new_data_acked = QuicStream::OnStreamFrameAcked( |
| 581 | offset, data_length, fin_acked, ack_delay_time, newly_acked_length); |
| 582 | |
| 583 | const QuicByteCount newly_acked_header_length = |
| 584 | GetNumFrameHeadersInInterval(offset, data_length); |
| 585 | DCHECK_LE(newly_acked_header_length, *newly_acked_length); |
| 586 | unacked_frame_headers_offsets_.Difference(offset, offset + data_length); |
| 587 | if (ack_listener_ != nullptr && new_data_acked) { |
| 588 | ack_listener_->OnPacketAcked( |
| 589 | *newly_acked_length - newly_acked_header_length, ack_delay_time); |
| 590 | } |
| 591 | return new_data_acked; |
| 592 | } |
| 593 | |
| 594 | void QuicSpdyStream::OnStreamFrameRetransmitted(QuicStreamOffset offset, |
| 595 | QuicByteCount data_length, |
| 596 | bool fin_retransmitted) { |
| 597 | QuicStream::OnStreamFrameRetransmitted(offset, data_length, |
| 598 | fin_retransmitted); |
| 599 | |
| 600 | const QuicByteCount retransmitted_header_length = |
| 601 | GetNumFrameHeadersInInterval(offset, data_length); |
| 602 | DCHECK_LE(retransmitted_header_length, data_length); |
| 603 | |
| 604 | if (ack_listener_ != nullptr) { |
| 605 | ack_listener_->OnPacketRetransmitted(data_length - |
| 606 | retransmitted_header_length); |
| 607 | } |
| 608 | } |
| 609 | |
| 610 | QuicByteCount QuicSpdyStream::GetNumFrameHeadersInInterval( |
| 611 | QuicStreamOffset offset, |
| 612 | QuicByteCount data_length) const { |
| 613 | QuicByteCount header_acked_length = 0; |
| 614 | QuicIntervalSet<QuicStreamOffset> newly_acked(offset, offset + data_length); |
| 615 | newly_acked.Intersection(unacked_frame_headers_offsets_); |
| 616 | for (const auto& interval : newly_acked) { |
| 617 | header_acked_length += interval.Length(); |
| 618 | } |
| 619 | return header_acked_length; |
| 620 | } |
| 621 | |
| 622 | #undef ENDPOINT // undef for jumbo builds |
| 623 | } // namespace quic |