OLD | NEW |
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/quic/reliable_quic_stream.h" | 5 #include "net/quic/reliable_quic_stream.h" |
6 | 6 |
7 #include "net/quic/quic_ack_notifier.h" | 7 #include "net/quic/quic_ack_notifier.h" |
8 #include "net/quic/quic_connection.h" | 8 #include "net/quic/quic_connection.h" |
9 #include "net/quic/quic_spdy_compressor.h" | 9 #include "net/quic/quic_spdy_compressor.h" |
10 #include "net/quic/quic_spdy_decompressor.h" | 10 #include "net/quic/quic_spdy_decompressor.h" |
(...skipping 25 matching lines...) Expand all Loading... |
36 const bool kShouldProcessData = true; | 36 const bool kShouldProcessData = true; |
37 | 37 |
38 class TestStream : public ReliableQuicStream { | 38 class TestStream : public ReliableQuicStream { |
39 public: | 39 public: |
40 TestStream(QuicStreamId id, | 40 TestStream(QuicStreamId id, |
41 QuicSession* session, | 41 QuicSession* session, |
42 bool should_process_data) | 42 bool should_process_data) |
43 : ReliableQuicStream(id, session), | 43 : ReliableQuicStream(id, session), |
44 should_process_data_(should_process_data) {} | 44 should_process_data_(should_process_data) {} |
45 | 45 |
46 virtual uint32 ProcessData(const char* data, uint32 data_len) OVERRIDE { | 46 virtual uint32 ProcessRawData(const char* data, uint32 data_len) OVERRIDE { |
47 EXPECT_NE(0u, data_len); | 47 EXPECT_NE(0u, data_len); |
48 DVLOG(1) << "ProcessData data_len: " << data_len; | 48 DVLOG(1) << "ProcessData data_len: " << data_len; |
49 data_ += string(data, data_len); | 49 data_ += string(data, data_len); |
50 return should_process_data_ ? data_len : 0; | 50 return should_process_data_ ? data_len : 0; |
51 } | 51 } |
52 | 52 |
| 53 virtual QuicPriority EffectivePriority() const OVERRIDE { return 0; } |
| 54 |
53 using ReliableQuicStream::WriteOrBufferData; | 55 using ReliableQuicStream::WriteOrBufferData; |
54 using ReliableQuicStream::CloseReadSide; | 56 using ReliableQuicStream::CloseReadSide; |
55 using ReliableQuicStream::CloseWriteSide; | 57 using ReliableQuicStream::CloseWriteSide; |
56 | 58 |
57 const string& data() const { return data_; } | 59 const string& data() const { return data_; } |
58 | 60 |
59 private: | 61 private: |
60 bool should_process_data_; | 62 bool should_process_data_; |
61 string data_; | 63 string data_; |
62 }; | 64 }; |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
219 | 221 |
220 stream_->CloseReadSide(); | 222 stream_->CloseReadSide(); |
221 stream_->CloseWriteSide(); | 223 stream_->CloseWriteSide(); |
222 EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_->stream_error()); | 224 EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_->stream_error()); |
223 EXPECT_EQ(QUIC_NO_ERROR, stream_->connection_error()); | 225 EXPECT_EQ(QUIC_NO_ERROR, stream_->connection_error()); |
224 stream_->OnConnectionClosed(QUIC_INTERNAL_ERROR, false); | 226 stream_->OnConnectionClosed(QUIC_INTERNAL_ERROR, false); |
225 EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_->stream_error()); | 227 EXPECT_EQ(QUIC_STREAM_NO_ERROR, stream_->stream_error()); |
226 EXPECT_EQ(QUIC_NO_ERROR, stream_->connection_error()); | 228 EXPECT_EQ(QUIC_NO_ERROR, stream_->connection_error()); |
227 } | 229 } |
228 | 230 |
229 TEST_F(ReliableQuicStreamTest, ProcessHeaders) { | |
230 Initialize(kShouldProcessData); | |
231 | |
232 string compressed_headers = compressor_->CompressHeadersWithPriority( | |
233 kHighestPriority, headers_); | |
234 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(compressed_headers)); | |
235 | |
236 stream_->OnStreamFrame(frame); | |
237 EXPECT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_), stream_->data()); | |
238 EXPECT_EQ(static_cast<QuicPriority>(kHighestPriority), | |
239 stream_->EffectivePriority()); | |
240 } | |
241 | |
242 TEST_F(ReliableQuicStreamTest, ProcessHeadersWithInvalidHeaderId) { | |
243 Initialize(kShouldProcessData); | |
244 | |
245 string compressed_headers = compressor_->CompressHeadersWithPriority( | |
246 kHighestPriority, headers_); | |
247 compressed_headers[4] = '\xFF'; // Illegal header id. | |
248 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(compressed_headers)); | |
249 | |
250 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_HEADER_ID)); | |
251 stream_->OnStreamFrame(frame); | |
252 } | |
253 | |
254 TEST_F(ReliableQuicStreamTest, ProcessHeadersWithInvalidPriority) { | |
255 Initialize(kShouldProcessData); | |
256 | |
257 string compressed_headers = compressor_->CompressHeadersWithPriority( | |
258 kHighestPriority, headers_); | |
259 compressed_headers[0] = '\xFF'; // Illegal priority. | |
260 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(compressed_headers)); | |
261 | |
262 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_PRIORITY)); | |
263 stream_->OnStreamFrame(frame); | |
264 } | |
265 | |
266 TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBody) { | |
267 Initialize(kShouldProcessData); | |
268 | |
269 string compressed_headers = compressor_->CompressHeadersWithPriority( | |
270 kHighestPriority, headers_); | |
271 string body = "this is the body"; | |
272 string data = compressed_headers + body; | |
273 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(data)); | |
274 | |
275 stream_->OnStreamFrame(frame); | |
276 EXPECT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_) + body, | |
277 stream_->data()); | |
278 } | |
279 | |
280 TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBodyFragments) { | |
281 Initialize(kShouldProcessData); | |
282 | |
283 string compressed_headers = compressor_->CompressHeadersWithPriority( | |
284 kLowestPriority, headers_); | |
285 string body = "this is the body"; | |
286 string data = compressed_headers + body; | |
287 | |
288 for (size_t fragment_size = 1; fragment_size < data.size(); ++fragment_size) { | |
289 Initialize(kShouldProcessData); | |
290 for (size_t offset = 0; offset < data.size(); offset += fragment_size) { | |
291 size_t remaining_data = data.length() - offset; | |
292 StringPiece fragment(data.data() + offset, | |
293 min(fragment_size, remaining_data)); | |
294 QuicStreamFrame frame(kStreamId, false, offset, MakeIOVector(fragment)); | |
295 | |
296 stream_->OnStreamFrame(frame); | |
297 } | |
298 ASSERT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_) + body, | |
299 stream_->data()) << "fragment_size: " << fragment_size; | |
300 } | |
301 | |
302 for (size_t split_point = 1; split_point < data.size() - 1; ++split_point) { | |
303 Initialize(kShouldProcessData); | |
304 | |
305 StringPiece fragment1(data.data(), split_point); | |
306 QuicStreamFrame frame1(kStreamId, false, 0, MakeIOVector(fragment1)); | |
307 stream_->OnStreamFrame(frame1); | |
308 | |
309 StringPiece fragment2(data.data() + split_point, data.size() - split_point); | |
310 QuicStreamFrame frame2( | |
311 kStreamId, false, split_point, MakeIOVector(fragment2)); | |
312 stream_->OnStreamFrame(frame2); | |
313 | |
314 ASSERT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers_) + body, | |
315 stream_->data()) << "split_point: " << split_point; | |
316 } | |
317 EXPECT_EQ(static_cast<QuicPriority>(kLowestPriority), | |
318 stream_->EffectivePriority()); | |
319 } | |
320 | |
321 TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBodyReadv) { | |
322 Initialize(!kShouldProcessData); | |
323 | |
324 string compressed_headers = compressor_->CompressHeadersWithPriority( | |
325 kHighestPriority, headers_); | |
326 string body = "this is the body"; | |
327 string data = compressed_headers + body; | |
328 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(data)); | |
329 string uncompressed_headers = | |
330 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
331 string uncompressed_data = uncompressed_headers + body; | |
332 | |
333 stream_->OnStreamFrame(frame); | |
334 EXPECT_EQ(uncompressed_headers, stream_->data()); | |
335 | |
336 char buffer[2048]; | |
337 ASSERT_LT(data.length(), arraysize(buffer)); | |
338 struct iovec vec; | |
339 vec.iov_base = buffer; | |
340 vec.iov_len = arraysize(buffer); | |
341 | |
342 size_t bytes_read = stream_->Readv(&vec, 1); | |
343 EXPECT_EQ(uncompressed_headers.length(), bytes_read); | |
344 EXPECT_EQ(uncompressed_headers, string(buffer, bytes_read)); | |
345 | |
346 bytes_read = stream_->Readv(&vec, 1); | |
347 EXPECT_EQ(body.length(), bytes_read); | |
348 EXPECT_EQ(body, string(buffer, bytes_read)); | |
349 } | |
350 | |
351 TEST_F(ReliableQuicStreamTest, ProcessHeadersAndBodyIncrementalReadv) { | |
352 Initialize(!kShouldProcessData); | |
353 | |
354 string compressed_headers = compressor_->CompressHeadersWithPriority( | |
355 kHighestPriority, headers_); | |
356 string body = "this is the body"; | |
357 string data = compressed_headers + body; | |
358 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(data)); | |
359 string uncompressed_headers = | |
360 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
361 string uncompressed_data = uncompressed_headers + body; | |
362 | |
363 stream_->OnStreamFrame(frame); | |
364 EXPECT_EQ(uncompressed_headers, stream_->data()); | |
365 | |
366 char buffer[1]; | |
367 struct iovec vec; | |
368 vec.iov_base = buffer; | |
369 vec.iov_len = arraysize(buffer); | |
370 for (size_t i = 0; i < uncompressed_data.length(); ++i) { | |
371 size_t bytes_read = stream_->Readv(&vec, 1); | |
372 ASSERT_EQ(1u, bytes_read); | |
373 EXPECT_EQ(uncompressed_data.data()[i], buffer[0]); | |
374 } | |
375 } | |
376 | |
377 TEST_F(ReliableQuicStreamTest, ProcessHeadersUsingReadvWithMultipleIovecs) { | |
378 Initialize(!kShouldProcessData); | |
379 | |
380 string compressed_headers = compressor_->CompressHeadersWithPriority( | |
381 kHighestPriority, headers_); | |
382 string body = "this is the body"; | |
383 string data = compressed_headers + body; | |
384 QuicStreamFrame frame(kStreamId, false, 0, MakeIOVector(data)); | |
385 string uncompressed_headers = | |
386 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
387 string uncompressed_data = uncompressed_headers + body; | |
388 | |
389 stream_->OnStreamFrame(frame); | |
390 EXPECT_EQ(uncompressed_headers, stream_->data()); | |
391 | |
392 char buffer1[1]; | |
393 char buffer2[1]; | |
394 struct iovec vec[2]; | |
395 vec[0].iov_base = buffer1; | |
396 vec[0].iov_len = arraysize(buffer1); | |
397 vec[1].iov_base = buffer2; | |
398 vec[1].iov_len = arraysize(buffer2); | |
399 for (size_t i = 0; i < uncompressed_data.length(); i += 2) { | |
400 size_t bytes_read = stream_->Readv(vec, 2); | |
401 ASSERT_EQ(2u, bytes_read) << i; | |
402 ASSERT_EQ(uncompressed_data.data()[i], buffer1[0]) << i; | |
403 ASSERT_EQ(uncompressed_data.data()[i + 1], buffer2[0]) << i; | |
404 } | |
405 } | |
406 | |
407 TEST_F(ReliableQuicStreamTest, ProcessCorruptHeadersEarly) { | |
408 Initialize(kShouldProcessData); | |
409 | |
410 string compressed_headers1 = compressor_->CompressHeadersWithPriority( | |
411 kHighestPriority, headers_); | |
412 QuicStreamFrame frame1( | |
413 stream_->id(), false, 0, MakeIOVector(compressed_headers1)); | |
414 string decompressed_headers1 = | |
415 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
416 | |
417 headers_["content-type"] = "text/plain"; | |
418 string compressed_headers2 = compressor_->CompressHeadersWithPriority( | |
419 kHighestPriority, headers_); | |
420 // Corrupt the compressed data. | |
421 compressed_headers2[compressed_headers2.length() - 1] ^= 0xA1; | |
422 QuicStreamFrame frame2( | |
423 stream2_->id(), false, 0, MakeIOVector(compressed_headers2)); | |
424 string decompressed_headers2 = | |
425 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
426 | |
427 // Deliver frame2 to stream2 out of order. The decompressor is not | |
428 // available yet, so no data will be processed. The compressed data | |
429 // will be buffered until OnDecompressorAvailable() is called | |
430 // to process it. | |
431 stream2_->OnStreamFrame(frame2); | |
432 EXPECT_EQ("", stream2_->data()); | |
433 | |
434 // Now deliver frame1 to stream1. The decompressor is available so | |
435 // the data will be processed, and the decompressor will become | |
436 // available for stream2. | |
437 stream_->OnStreamFrame(frame1); | |
438 EXPECT_EQ(decompressed_headers1, stream_->data()); | |
439 | |
440 // Verify that the decompressor is available, and inform stream2 | |
441 // that it can now decompress the buffered compressed data. Since | |
442 // the compressed data is corrupt, the stream will shutdown the session. | |
443 EXPECT_EQ(2u, session_->decompressor()->current_header_id()); | |
444 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_DECOMPRESSION_FAILURE)); | |
445 stream2_->OnDecompressorAvailable(); | |
446 EXPECT_EQ("", stream2_->data()); | |
447 } | |
448 | |
449 TEST_F(ReliableQuicStreamTest, ProcessPartialHeadersEarly) { | |
450 Initialize(kShouldProcessData); | |
451 | |
452 string compressed_headers1 = compressor_->CompressHeadersWithPriority( | |
453 kHighestPriority, headers_); | |
454 QuicStreamFrame frame1( | |
455 stream_->id(), false, 0, MakeIOVector(compressed_headers1)); | |
456 string decompressed_headers1 = | |
457 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
458 | |
459 headers_["content-type"] = "text/plain"; | |
460 string compressed_headers2 = compressor_->CompressHeadersWithPriority( | |
461 kHighestPriority, headers_); | |
462 string partial_compressed_headers = | |
463 compressed_headers2.substr(0, compressed_headers2.length() / 2); | |
464 QuicStreamFrame frame2( | |
465 stream2_->id(), false, 0, MakeIOVector(partial_compressed_headers)); | |
466 string decompressed_headers2 = | |
467 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
468 | |
469 // Deliver frame2 to stream2 out of order. The decompressor is not | |
470 // available yet, so no data will be processed. The compressed data | |
471 // will be buffered until OnDecompressorAvailable() is called | |
472 // to process it. | |
473 stream2_->OnStreamFrame(frame2); | |
474 EXPECT_EQ("", stream2_->data()); | |
475 | |
476 // Now deliver frame1 to stream1. The decompressor is available so | |
477 // the data will be processed, and the decompressor will become | |
478 // available for stream2. | |
479 stream_->OnStreamFrame(frame1); | |
480 EXPECT_EQ(decompressed_headers1, stream_->data()); | |
481 | |
482 // Verify that the decompressor is available, and inform stream2 | |
483 // that it can now decompress the buffered compressed data. Since | |
484 // the compressed data is incomplete it will not be passed to | |
485 // the stream. | |
486 EXPECT_EQ(2u, session_->decompressor()->current_header_id()); | |
487 stream2_->OnDecompressorAvailable(); | |
488 EXPECT_EQ("", stream2_->data()); | |
489 | |
490 // Now send remaining data and verify that we have now received the | |
491 // compressed headers. | |
492 string remaining_compressed_headers = | |
493 compressed_headers2.substr(partial_compressed_headers.length()); | |
494 | |
495 QuicStreamFrame frame3(stream2_->id(), false, | |
496 partial_compressed_headers.length(), | |
497 MakeIOVector(remaining_compressed_headers)); | |
498 stream2_->OnStreamFrame(frame3); | |
499 EXPECT_EQ(decompressed_headers2, stream2_->data()); | |
500 } | |
501 | |
502 TEST_F(ReliableQuicStreamTest, ProcessHeadersEarly) { | |
503 Initialize(kShouldProcessData); | |
504 | |
505 string compressed_headers1 = compressor_->CompressHeadersWithPriority( | |
506 kHighestPriority, headers_); | |
507 QuicStreamFrame frame1( | |
508 stream_->id(), false, 0, MakeIOVector(compressed_headers1)); | |
509 string decompressed_headers1 = | |
510 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
511 | |
512 headers_["content-type"] = "text/plain"; | |
513 string compressed_headers2 = compressor_->CompressHeadersWithPriority( | |
514 kHighestPriority, headers_); | |
515 QuicStreamFrame frame2( | |
516 stream2_->id(), false, 0, MakeIOVector(compressed_headers2)); | |
517 string decompressed_headers2 = | |
518 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
519 | |
520 // Deliver frame2 to stream2 out of order. The decompressor is not | |
521 // available yet, so no data will be processed. The compressed data | |
522 // will be buffered until OnDecompressorAvailable() is called | |
523 // to process it. | |
524 stream2_->OnStreamFrame(frame2); | |
525 EXPECT_EQ("", stream2_->data()); | |
526 | |
527 // Now deliver frame1 to stream1. The decompressor is available so | |
528 // the data will be processed, and the decompressor will become | |
529 // available for stream2. | |
530 stream_->OnStreamFrame(frame1); | |
531 EXPECT_EQ(decompressed_headers1, stream_->data()); | |
532 | |
533 // Verify that the decompressor is available, and inform stream2 | |
534 // that it can now decompress the buffered compressed data. | |
535 EXPECT_EQ(2u, session_->decompressor()->current_header_id()); | |
536 stream2_->OnDecompressorAvailable(); | |
537 EXPECT_EQ(decompressed_headers2, stream2_->data()); | |
538 } | |
539 | |
540 TEST_F(ReliableQuicStreamTest, ProcessHeadersDelay) { | |
541 Initialize(!kShouldProcessData); | |
542 | |
543 string compressed_headers = compressor_->CompressHeadersWithPriority( | |
544 kHighestPriority, headers_); | |
545 QuicStreamFrame frame1( | |
546 stream_->id(), false, 0, MakeIOVector(compressed_headers)); | |
547 string decompressed_headers = | |
548 SpdyUtils::SerializeUncompressedHeaders(headers_); | |
549 | |
550 // Send the headers to the stream and verify they were decompressed. | |
551 stream_->OnStreamFrame(frame1); | |
552 EXPECT_EQ(2u, session_->decompressor()->current_header_id()); | |
553 | |
554 // Verify that we are now able to handle the body data, | |
555 // even though the stream has not processed the headers. | |
556 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_HEADER_ID)) | |
557 .Times(0); | |
558 QuicStreamFrame frame2(stream_->id(), false, compressed_headers.length(), | |
559 MakeIOVector("body data")); | |
560 stream_->OnStreamFrame(frame2); | |
561 } | |
562 | |
563 } // namespace | 231 } // namespace |
564 } // namespace test | 232 } // namespace test |
565 } // namespace net | 233 } // namespace net |
OLD | NEW |