| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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/quic/core/quic_spdy_stream.h" | 5 #include "net/quic/core/quic_spdy_stream.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 139 } | 139 } |
| 140 | 140 |
| 141 bool QuicSpdyStream::IsDoneReading() const { | 141 bool QuicSpdyStream::IsDoneReading() const { |
| 142 bool done_reading_headers = FinishedReadingHeaders(); | 142 bool done_reading_headers = FinishedReadingHeaders(); |
| 143 bool done_reading_body = sequencer()->IsClosed(); | 143 bool done_reading_body = sequencer()->IsClosed(); |
| 144 bool done_reading_trailers = FinishedReadingTrailers(); | 144 bool done_reading_trailers = FinishedReadingTrailers(); |
| 145 return done_reading_headers && done_reading_body && done_reading_trailers; | 145 return done_reading_headers && done_reading_body && done_reading_trailers; |
| 146 } | 146 } |
| 147 | 147 |
| 148 bool QuicSpdyStream::HasBytesToRead() const { | 148 bool QuicSpdyStream::HasBytesToRead() const { |
| 149 bool headers_to_read = !decompressed_headers_.empty(); | 149 return sequencer()->HasBytesToRead(); |
| 150 bool body_to_read = sequencer()->HasBytesToRead(); | |
| 151 bool trailers_to_read = !decompressed_trailers_.empty(); | |
| 152 return headers_to_read || body_to_read || trailers_to_read; | |
| 153 } | |
| 154 | |
| 155 void QuicSpdyStream::MarkHeadersConsumed(size_t bytes_consumed) { | |
| 156 decompressed_headers_.erase(0, bytes_consumed); | |
| 157 if (FinishedReadingHeaders()) { | |
| 158 sequencer()->SetUnblocked(); | |
| 159 } | |
| 160 } | |
| 161 | |
| 162 void QuicSpdyStream::MarkTrailersConsumed(size_t bytes_consumed) { | |
| 163 decompressed_trailers_.erase(0, bytes_consumed); | |
| 164 } | 150 } |
| 165 | 151 |
| 166 void QuicSpdyStream::MarkTrailersConsumed() { | 152 void QuicSpdyStream::MarkTrailersConsumed() { |
| 167 trailers_consumed_ = true; | 153 trailers_consumed_ = true; |
| 168 } | 154 } |
| 169 | 155 |
| 170 void QuicSpdyStream::ConsumeHeaderList() { | 156 void QuicSpdyStream::ConsumeHeaderList() { |
| 171 header_list_.Clear(); | 157 header_list_.Clear(); |
| 172 if (FinishedReadingHeaders()) { | 158 if (FinishedReadingHeaders()) { |
| 173 sequencer()->SetUnblocked(); | 159 sequencer()->SetUnblocked(); |
| 174 } | 160 } |
| 175 } | 161 } |
| 176 | 162 |
| 177 void QuicSpdyStream::SetPriority(SpdyPriority priority) { | 163 void QuicSpdyStream::SetPriority(SpdyPriority priority) { |
| 178 DCHECK_EQ(0u, stream_bytes_written()); | 164 DCHECK_EQ(0u, stream_bytes_written()); |
| 179 spdy_session_->UpdateStreamPriority(id(), priority); | 165 spdy_session_->UpdateStreamPriority(id(), priority); |
| 180 priority_ = priority; | 166 priority_ = priority; |
| 181 } | 167 } |
| 182 | 168 |
| 183 void QuicSpdyStream::OnStreamHeaders(StringPiece headers_data) { | |
| 184 if (!headers_decompressed_) { | |
| 185 headers_data.AppendToString(&decompressed_headers_); | |
| 186 } else { | |
| 187 DCHECK(!trailers_decompressed_); | |
| 188 headers_data.AppendToString(&decompressed_trailers_); | |
| 189 } | |
| 190 } | |
| 191 | |
| 192 void QuicSpdyStream::OnStreamHeadersPriority(SpdyPriority priority) { | 169 void QuicSpdyStream::OnStreamHeadersPriority(SpdyPriority priority) { |
| 193 DCHECK_EQ(Perspective::IS_SERVER, session()->connection()->perspective()); | 170 DCHECK_EQ(Perspective::IS_SERVER, session()->connection()->perspective()); |
| 194 SetPriority(priority); | 171 SetPriority(priority); |
| 195 } | 172 } |
| 196 | 173 |
| 197 void QuicSpdyStream::OnStreamHeadersComplete(bool fin, size_t frame_len) { | |
| 198 if (!headers_decompressed_) { | |
| 199 OnInitialHeadersComplete(fin, frame_len); | |
| 200 } else { | |
| 201 OnTrailingHeadersComplete(fin, frame_len); | |
| 202 } | |
| 203 } | |
| 204 | |
| 205 void QuicSpdyStream::OnStreamHeaderList(bool fin, | 174 void QuicSpdyStream::OnStreamHeaderList(bool fin, |
| 206 size_t frame_len, | 175 size_t frame_len, |
| 207 const QuicHeaderList& header_list) { | 176 const QuicHeaderList& header_list) { |
| 208 // The headers list avoid infinite buffering by clearing the headers list | 177 // The headers list avoid infinite buffering by clearing the headers list |
| 209 // if the current headers are too large. So if the list is empty here | 178 // if the current headers are too large. So if the list is empty here |
| 210 // then the headers list must have been too large, and the stream should | 179 // then the headers list must have been too large, and the stream should |
| 211 // be reset. | 180 // be reset. |
| 181 // TODO(rch): Use an explicit "headers too large" signal. An empty header list |
| 182 // might be acceptable if it corresponds to a trailing header frame. |
| 212 if (FLAGS_quic_limit_uncompressed_headers && header_list.empty()) { | 183 if (FLAGS_quic_limit_uncompressed_headers && header_list.empty()) { |
| 213 OnHeadersTooLarge(); | 184 OnHeadersTooLarge(); |
| 214 if (IsDoneReading()) { | 185 if (IsDoneReading()) { |
| 215 return; | 186 return; |
| 216 } | 187 } |
| 217 } | 188 } |
| 218 if (!headers_decompressed_) { | 189 if (!headers_decompressed_) { |
| 219 OnInitialHeadersComplete(fin, frame_len, header_list); | 190 OnInitialHeadersComplete(fin, frame_len, header_list); |
| 220 } else { | 191 } else { |
| 221 OnTrailingHeadersComplete(fin, frame_len, header_list); | 192 OnTrailingHeadersComplete(fin, frame_len, header_list); |
| 222 } | 193 } |
| 223 } | 194 } |
| 224 | 195 |
| 225 void QuicSpdyStream::OnHeadersTooLarge() { | 196 void QuicSpdyStream::OnHeadersTooLarge() { |
| 226 Reset(QUIC_HEADERS_TOO_LARGE); | 197 Reset(QUIC_HEADERS_TOO_LARGE); |
| 227 } | 198 } |
| 228 | 199 |
| 229 void QuicSpdyStream::OnInitialHeadersComplete(bool fin, size_t /*frame_len*/) { | |
| 230 headers_decompressed_ = true; | |
| 231 if (fin) { | |
| 232 OnStreamFrame(QuicStreamFrame(id(), fin, 0, StringPiece())); | |
| 233 } | |
| 234 if (FinishedReadingHeaders()) { | |
| 235 sequencer()->SetUnblocked(); | |
| 236 } | |
| 237 } | |
| 238 | |
| 239 void QuicSpdyStream::OnInitialHeadersComplete( | 200 void QuicSpdyStream::OnInitialHeadersComplete( |
| 240 bool fin, | 201 bool fin, |
| 241 size_t /*frame_len*/, | 202 size_t /*frame_len*/, |
| 242 const QuicHeaderList& header_list) { | 203 const QuicHeaderList& header_list) { |
| 243 headers_decompressed_ = true; | 204 headers_decompressed_ = true; |
| 244 header_list_ = header_list; | 205 header_list_ = header_list; |
| 245 if (fin) { | 206 if (fin) { |
| 246 OnStreamFrame(QuicStreamFrame(id(), fin, 0, StringPiece())); | 207 OnStreamFrame(QuicStreamFrame(id(), fin, 0, StringPiece())); |
| 247 } | 208 } |
| 248 if (FinishedReadingHeaders()) { | 209 if (FinishedReadingHeaders()) { |
| 249 sequencer()->SetUnblocked(); | 210 sequencer()->SetUnblocked(); |
| 250 } | 211 } |
| 251 } | 212 } |
| 252 | 213 |
| 253 void QuicSpdyStream::OnPromiseHeaders(StringPiece headers_data) { | |
| 254 headers_data.AppendToString(&decompressed_headers_); | |
| 255 } | |
| 256 | |
| 257 void QuicSpdyStream::OnPromiseHeadersComplete( | |
| 258 QuicStreamId /* promised_stream_id */, | |
| 259 size_t /* frame_len */) { | |
| 260 // To be overridden in QuicSpdyClientStream. Not supported on | |
| 261 // server side. | |
| 262 session()->connection()->CloseConnection( | |
| 263 QUIC_INVALID_HEADERS_STREAM_DATA, "Promise headers received by server", | |
| 264 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); | |
| 265 return; | |
| 266 } | |
| 267 | |
| 268 void QuicSpdyStream::OnPromiseHeaderList( | 214 void QuicSpdyStream::OnPromiseHeaderList( |
| 269 QuicStreamId /* promised_id */, | 215 QuicStreamId /* promised_id */, |
| 270 size_t /* frame_len */, | 216 size_t /* frame_len */, |
| 271 const QuicHeaderList& /*header_list */) { | 217 const QuicHeaderList& /*header_list */) { |
| 272 // To be overridden in QuicSpdyClientStream. Not supported on | 218 // To be overridden in QuicSpdyClientStream. Not supported on |
| 273 // server side. | 219 // server side. |
| 274 session()->connection()->CloseConnection( | 220 session()->connection()->CloseConnection( |
| 275 QUIC_INVALID_HEADERS_STREAM_DATA, "Promise headers received by server", | 221 QUIC_INVALID_HEADERS_STREAM_DATA, "Promise headers received by server", |
| 276 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); | 222 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); |
| 277 return; | 223 return; |
| 278 } | 224 } |
| 279 | 225 |
| 280 void QuicSpdyStream::OnTrailingHeadersComplete(bool fin, size_t /*frame_len*/) { | |
| 281 DCHECK(!trailers_decompressed_); | |
| 282 if (fin_received()) { | |
| 283 DLOG(ERROR) << "Received Trailers after FIN, on stream: " << id(); | |
| 284 session()->connection()->CloseConnection( | |
| 285 QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers after fin", | |
| 286 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); | |
| 287 return; | |
| 288 } | |
| 289 if (!fin) { | |
| 290 DLOG(ERROR) << "Trailers must have FIN set, on stream: " << id(); | |
| 291 session()->connection()->CloseConnection( | |
| 292 QUIC_INVALID_HEADERS_STREAM_DATA, "Fin missing from trailers", | |
| 293 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); | |
| 294 return; | |
| 295 } | |
| 296 | |
| 297 size_t final_byte_offset = 0; | |
| 298 if (!SpdyUtils::ParseTrailers(decompressed_trailers().data(), | |
| 299 decompressed_trailers().length(), | |
| 300 &final_byte_offset, &received_trailers_)) { | |
| 301 DLOG(ERROR) << "Trailers are malformed: " << id(); | |
| 302 session()->connection()->CloseConnection( | |
| 303 QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers are malformed", | |
| 304 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); | |
| 305 return; | |
| 306 } | |
| 307 | |
| 308 // The data on this stream ends at |final_byte_offset|. | |
| 309 DVLOG(1) << "Stream ends at byte offset: " << final_byte_offset | |
| 310 << " currently read: " << stream_bytes_read(); | |
| 311 trailers_decompressed_ = true; | |
| 312 OnStreamFrame(QuicStreamFrame(id(), fin, final_byte_offset, StringPiece())); | |
| 313 } | |
| 314 | |
| 315 void QuicSpdyStream::OnTrailingHeadersComplete( | 226 void QuicSpdyStream::OnTrailingHeadersComplete( |
| 316 bool fin, | 227 bool fin, |
| 317 size_t /*frame_len*/, | 228 size_t /*frame_len*/, |
| 318 const QuicHeaderList& header_list) { | 229 const QuicHeaderList& header_list) { |
| 319 DCHECK(!trailers_decompressed_); | 230 DCHECK(!trailers_decompressed_); |
| 320 if (fin_received()) { | 231 if (fin_received()) { |
| 321 DLOG(ERROR) << "Received Trailers after FIN, on stream: " << id(); | 232 DLOG(ERROR) << "Received Trailers after FIN, on stream: " << id(); |
| 322 session()->connection()->CloseConnection( | 233 session()->connection()->CloseConnection( |
| 323 QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers after fin", | 234 QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers after fin", |
| 324 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); | 235 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 372 void QuicSpdyStream::OnCanWrite() { | 283 void QuicSpdyStream::OnCanWrite() { |
| 373 ReliableQuicStream::OnCanWrite(); | 284 ReliableQuicStream::OnCanWrite(); |
| 374 | 285 |
| 375 // Trailers (and hence a FIN) may have been sent ahead of queued body bytes. | 286 // Trailers (and hence a FIN) may have been sent ahead of queued body bytes. |
| 376 if (!HasBufferedData() && fin_sent()) { | 287 if (!HasBufferedData() && fin_sent()) { |
| 377 CloseWriteSide(); | 288 CloseWriteSide(); |
| 378 } | 289 } |
| 379 } | 290 } |
| 380 | 291 |
| 381 bool QuicSpdyStream::FinishedReadingHeaders() const { | 292 bool QuicSpdyStream::FinishedReadingHeaders() const { |
| 382 return headers_decompressed_ && decompressed_headers_.empty() && | 293 return headers_decompressed_ && header_list_.empty(); |
| 383 header_list_.empty(); | |
| 384 } | 294 } |
| 385 | 295 |
| 386 bool QuicSpdyStream::ParseHeaderStatusCode(const SpdyHeaderBlock& header, | 296 bool QuicSpdyStream::ParseHeaderStatusCode(const SpdyHeaderBlock& header, |
| 387 int* status_code) const { | 297 int* status_code) const { |
| 388 SpdyHeaderBlock::const_iterator it = header.find(":status"); | 298 SpdyHeaderBlock::const_iterator it = header.find(":status"); |
| 389 if (it == header.end()) { | 299 if (it == header.end()) { |
| 390 return false; | 300 return false; |
| 391 } | 301 } |
| 392 const StringPiece status(it->second); | 302 const StringPiece status(it->second); |
| 393 if (status.size() != 3) { | 303 if (status.size() != 3) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 405 } | 315 } |
| 406 | 316 |
| 407 bool QuicSpdyStream::FinishedReadingTrailers() const { | 317 bool QuicSpdyStream::FinishedReadingTrailers() const { |
| 408 // If no further trailing headers are expected, and the decompressed trailers | 318 // If no further trailing headers are expected, and the decompressed trailers |
| 409 // (if any) have been consumed, then reading of trailers is finished. | 319 // (if any) have been consumed, then reading of trailers is finished. |
| 410 if (!fin_received()) { | 320 if (!fin_received()) { |
| 411 return false; | 321 return false; |
| 412 } else if (!trailers_decompressed_) { | 322 } else if (!trailers_decompressed_) { |
| 413 return true; | 323 return true; |
| 414 } else { | 324 } else { |
| 415 return trailers_consumed_ && decompressed_trailers_.empty(); | 325 return trailers_consumed_; |
| 416 } | 326 } |
| 417 } | 327 } |
| 418 | 328 |
| 419 SpdyPriority QuicSpdyStream::priority() const { | 329 SpdyPriority QuicSpdyStream::priority() const { |
| 420 return priority_; | 330 return priority_; |
| 421 } | 331 } |
| 422 | 332 |
| 423 void QuicSpdyStream::ClearSession() { | 333 void QuicSpdyStream::ClearSession() { |
| 424 spdy_session_ = nullptr; | 334 spdy_session_ = nullptr; |
| 425 } | 335 } |
| 426 | 336 |
| 427 QuicConsumedData QuicSpdyStream::WritevDataInner( | 337 QuicConsumedData QuicSpdyStream::WritevDataInner( |
| 428 QuicIOVector iov, | 338 QuicIOVector iov, |
| 429 QuicStreamOffset offset, | 339 QuicStreamOffset offset, |
| 430 bool fin, | 340 bool fin, |
| 431 QuicAckListenerInterface* ack_notifier_delegate) { | 341 QuicAckListenerInterface* ack_notifier_delegate) { |
| 432 if (spdy_session_->headers_stream() != nullptr && | 342 if (spdy_session_->headers_stream() != nullptr && |
| 433 spdy_session_->force_hol_blocking()) { | 343 spdy_session_->force_hol_blocking()) { |
| 434 return spdy_session_->headers_stream()->WritevStreamData( | 344 return spdy_session_->headers_stream()->WritevStreamData( |
| 435 id(), iov, offset, fin, ack_notifier_delegate); | 345 id(), iov, offset, fin, ack_notifier_delegate); |
| 436 } | 346 } |
| 437 return ReliableQuicStream::WritevDataInner(iov, offset, fin, | 347 return ReliableQuicStream::WritevDataInner(iov, offset, fin, |
| 438 ack_notifier_delegate); | 348 ack_notifier_delegate); |
| 439 } | 349 } |
| 440 | 350 |
| 441 } // namespace net | 351 } // namespace net |
| OLD | NEW |