From 20cea7f69386c74676fb0e6765a3e6eb3df3d0bd Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 11 Jul 2010 14:15:36 +0000 Subject: [PATCH] 2010-07-11 Tatsuhiro Tsujikawa Fixed ChunkedDecoder. It does not read trailer and final CRLF. * src/ChunkedDecoder.cc * src/ChunkedDecoder.h * test/ChunkedDecoderTest.cc --- ChangeLog | 7 +++++++ src/ChunkedDecoder.cc | 31 +++++++++++++++++++++++++++++-- src/ChunkedDecoder.h | 1 + test/ChunkedDecoderTest.cc | 25 +++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4d87a3d7..2b8a4487 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2010-07-11 Tatsuhiro Tsujikawa + + Fixed ChunkedDecoder. It does not read trailer and final CRLF. + * src/ChunkedDecoder.cc + * src/ChunkedDecoder.h + * test/ChunkedDecoderTest.cc + 2010-07-10 Tatsuhiro Tsujikawa Removed unusable typedefs diff --git a/src/ChunkedDecoder.cc b/src/ChunkedDecoder.cc index 57f1d722..55068545 100644 --- a/src/ChunkedDecoder.cc +++ b/src/ChunkedDecoder.cc @@ -64,6 +64,27 @@ static bool readChunkSize(uint64_t& chunkSize, std::string& in) return true; } +static bool readTrailer(std::string& in) +{ + std::string::size_type crlfPos = in.find(A2STR::CRLF); + if(crlfPos == std::string::npos) { + return false; + } + if(crlfPos == 0) { + return true; + } else { + if(in.size() > crlfPos+3) { + if(in[crlfPos+2] == '\r' && in[crlfPos+3] == '\n') { + return true; + } else { + throw DL_ABORT_EX("No CRLF at the end of chunk stream."); + } + } else { + return false; + } + } +} + static bool readData(std::string& out, uint64_t& chunkSize, std::string& in) { uint64_t readlen = std::min(chunkSize, static_cast(in.size())); @@ -91,8 +112,7 @@ std::string ChunkedDecoder::decode(const unsigned char* inbuf, size_t inlen) if(state_ == READ_SIZE) { if(readChunkSize(chunkSize_, buf_)) { if(chunkSize_ == 0) { - state_ = STREAM_END; - break; + state_ = READ_TRAILER; } else { state_ = READ_DATA; } @@ -105,6 +125,13 @@ std::string ChunkedDecoder::decode(const unsigned char* inbuf, size_t inlen) } else { break; } + } else if(state_ == READ_TRAILER) { + if(readTrailer(buf_)) { + state_ = STREAM_END; + break; + } else { + break; + } } } return outbuf; diff --git a/src/ChunkedDecoder.h b/src/ChunkedDecoder.h index 1a5fcc7f..60d2b830 100644 --- a/src/ChunkedDecoder.h +++ b/src/ChunkedDecoder.h @@ -44,6 +44,7 @@ private: enum STATE { READ_SIZE, READ_DATA, + READ_TRAILER, STREAM_END }; diff --git a/test/ChunkedDecoderTest.cc b/test/ChunkedDecoderTest.cc index eb54fd88..ce472982 100644 --- a/test/ChunkedDecoderTest.cc +++ b/test/ChunkedDecoderTest.cc @@ -9,6 +9,7 @@ class ChunkedDecoderTest:public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ChunkedDecoderTest); CPPUNIT_TEST(testDecode); + CPPUNIT_TEST(testDecode_withoutTrailer); CPPUNIT_TEST(testDecode_tooLargeChunkSize); CPPUNIT_TEST(testDecode_chunkSizeMismatch); CPPUNIT_TEST(testGetName); @@ -17,6 +18,7 @@ public: void setUp() {} void testDecode(); + void testDecode_withoutTrailer(); void testDecode_tooLargeChunkSize(); void testDecode_chunkSizeMismatch(); void testGetName(); @@ -102,12 +104,35 @@ void ChunkedDecoderTest::testDecode() CPPUNIT_ASSERT_EQUAL(std::string(), decoder.decode(msg.c_str(), msg.size())); } + // feed trailer + { + CPPUNIT_ASSERT_EQUAL + (std::string(), + decoder.decode + (reinterpret_cast("trailer\r\n"), 9)); + } + // feed final CRLF + { + CPPUNIT_ASSERT_EQUAL + (std::string(), + decoder.decode(reinterpret_cast("\r\n"), 2)); + } // input is over CPPUNIT_ASSERT(decoder.finished()); decoder.release(); } +void ChunkedDecoderTest::testDecode_withoutTrailer() +{ + ChunkedDecoder decoder; + decoder.init(); + CPPUNIT_ASSERT_EQUAL + (std::string(), + decoder.decode(reinterpret_cast("0\r\n\r\n"), 5)); + CPPUNIT_ASSERT(decoder.finished()); +} + void ChunkedDecoderTest::testDecode_tooLargeChunkSize() { // chunkSize should be under 2^64-1