Browse Source

2010-07-11 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	Fixed ChunkedDecoder. It does not read trailer and final CRLF.
	* src/ChunkedDecoder.cc
	* src/ChunkedDecoder.h
	* test/ChunkedDecoderTest.cc
Tatsuhiro Tsujikawa 15 năm trước cách đây
mục cha
commit
20cea7f693
4 tập tin đã thay đổi với 62 bổ sung2 xóa
  1. 7 0
      ChangeLog
  2. 29 2
      src/ChunkedDecoder.cc
  3. 1 0
      src/ChunkedDecoder.h
  4. 25 0
      test/ChunkedDecoderTest.cc

+ 7 - 0
ChangeLog

@@ -1,3 +1,10 @@
+2010-07-11  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	Fixed ChunkedDecoder. It does not read trailer and final CRLF.
+	* src/ChunkedDecoder.cc
+	* src/ChunkedDecoder.h
+	* test/ChunkedDecoderTest.cc
+
 2010-07-10  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	Removed unusable typedefs

+ 29 - 2
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<uint64_t>(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;

+ 1 - 0
src/ChunkedDecoder.h

@@ -44,6 +44,7 @@ private:
   enum STATE {
     READ_SIZE,
     READ_DATA,
+    READ_TRAILER,
     STREAM_END
   };
 

+ 25 - 0
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<const unsigned char*>("trailer\r\n"), 9));
+  }
+  // feed final CRLF
+  {
+    CPPUNIT_ASSERT_EQUAL
+      (std::string(),
+       decoder.decode(reinterpret_cast<const unsigned char*>("\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<const unsigned char*>("0\r\n\r\n"), 5));
+  CPPUNIT_ASSERT(decoder.finished());
+}
+
 void ChunkedDecoderTest::testDecode_tooLargeChunkSize()
 {
   // chunkSize should be under 2^64-1