소스 검색

2009-04-17 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	Fixed segmentation fault when GZipDecoder::decode() returns 0
	byte.
	* src/DownloadCommand.cc
	* src/bitfield.h
	* test/bitfieldTest.cc

	Fixed the bug that causes infinite loop if broken web server
	returns chunked response without last "0" chunk-size marker and
	closes connection.
	* src/DownloadCommand.cc

	Instantiate properly configured HttpDownloadCommand for
	non-resumable downlaods.
	* src/HttpResponseCommand.cc
Tatsuhiro Tsujikawa 16 년 전
부모
커밋
65a358c68b
5개의 변경된 파일52개의 추가작업 그리고 9개의 파일을 삭제
  1. 17 0
      ChangeLog
  2. 8 6
      src/DownloadCommand.cc
  3. 23 3
      src/HttpResponseCommand.cc
  4. 3 0
      src/bitfield.h
  5. 1 0
      test/bitfieldTest.cc

+ 17 - 0
ChangeLog

@@ -1,3 +1,20 @@
+2009-04-17  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	Fixed segmentation fault when GZipDecoder::decode() returns 0
+	byte.
+	* src/DownloadCommand.cc
+	* src/bitfield.h
+	* test/bitfieldTest.cc
+
+	Fixed the bug that causes infinite loop if broken web server
+	returns chunked response without last "0" chunk-size marker and
+	closes connection.
+	* src/DownloadCommand.cc
+
+	Instantiate properly configured HttpDownloadCommand for
+	non-resumable downlaods.
+	* src/HttpResponseCommand.cc
+	
 2009-04-16  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	Rewritten array operation functions.

+ 8 - 6
src/DownloadCommand.cc

@@ -156,17 +156,14 @@ bool DownloadCommand::executeInternal() {
   }
 
 #endif // ENABLE_MESSAGE_DIGEST
+  if(bufSizeFinal > 0) {
+    segment->updateWrittenLength(bufSizeFinal);
+  }
 
-  segment->updateWrittenLength(bufSizeFinal);
-  
   peerStat->updateDownloadLength(bufSize);
 
   _requestGroup->getSegmentMan()->updateDownloadSpeedFor(peerStat);
 
-  if(_requestGroup->getTotalLength() != 0 && bufSize == 0 &&
-     !socket->wantRead() && !socket->wantWrite()) {
-    throw DlRetryEx(EX_GOT_EOF);
-  }
   bool segmentComplete = false;
   if(_transferEncodingDecoder.isNull() && _contentEncodingDecoder.isNull()) {
     if(segment->complete()) {
@@ -193,6 +190,11 @@ bool DownloadCommand::executeInternal() {
     }
   }
 
+  if(!segmentComplete && bufSize == 0 &&
+     !socket->wantRead() && !socket->wantWrite()) {
+    throw DlRetryEx(EX_GOT_EOF);
+  }
+
   if(segmentComplete) {
     logger->info(MSG_SEGMENT_DOWNLOAD_COMPLETED, cuid);
 #ifdef ENABLE_MESSAGE_DIGEST

+ 23 - 3
src/HttpResponseCommand.cc

@@ -68,6 +68,12 @@
 
 namespace aria2 {
 
+static SharedHandle<Decoder> getTransferEncodingDecoder
+(const SharedHandle<HttpResponse>& httpResponse);
+
+static SharedHandle<Decoder> getContentEncodingDecoder
+(const SharedHandle<HttpResponse>& httpResponse);
+
 HttpResponseCommand::HttpResponseCommand(int32_t cuid,
 					 const RequestHandle& req,
 					 RequestGroup* requestGroup,
@@ -147,6 +153,8 @@ bool HttpResponseCommand::executeInternal()
       if(req->getMethod() == Request::METHOD_GET &&
 	 (totalLength != 0 ||
 	  !httpResponse->getHttpHeader()->defined(HttpHeader::CONTENT_LENGTH))){
+	// dctx->knowsTotalLength() == true only when server says the
+	// size of file is 0 explicitly.
 	dctx->markTotalLengthIsUnknown();
       }
       return handleOtherEncoding(httpResponse);
@@ -158,8 +166,19 @@ bool HttpResponseCommand::executeInternal()
     _requestGroup->validateTotalLength(httpResponse->getEntityLength());
     // update last modified time
     updateLastModifiedTime(httpResponse->getLastModifiedTime());
-
-    e->commands.push_back(createHttpDownloadCommand(httpResponse));
+    if(_requestGroup->getTotalLength() == 0) {
+      // Since total length is unknown, the file size in previously
+      // failed download could be larger than the size this time.
+      // Also we can't resume in this case too.  So truncate the file
+      // anyway.
+      _requestGroup->getPieceStorage()->getDiskAdaptor()->truncate(0);
+      e->commands.push_back
+	(createHttpDownloadCommand(httpResponse,
+				   getTransferEncodingDecoder(httpResponse),
+				   getContentEncodingDecoder(httpResponse)));
+    } else {
+      e->commands.push_back(createHttpDownloadCommand(httpResponse));
+    }
     return true;
   }
 }
@@ -299,11 +318,12 @@ bool HttpResponseCommand::handleOtherEncoding(const HttpResponseHandle& httpResp
   _requestGroup->shouldCancelDownloadForSafety();
   _requestGroup->getPieceStorage()->getDiskAdaptor()->initAndOpenFile();
 
+  // In this context, knowsTotalLength() is true only when the file is
+  // really zero-length.
   if(_requestGroup->getDownloadContext()->knowsTotalLength()) {
     poolConnection();
     return true;
   }
-
   e->commands.push_back
     (createHttpDownloadCommand(httpResponse,
 			       getTransferEncodingDecoder(httpResponse),

+ 3 - 0
src/bitfield.h

@@ -91,6 +91,9 @@ inline size_t countBit32(uint32_t n)
 // Counts set bit in bitfield.
 inline size_t countSetBit(const unsigned char* bitfield, size_t nbits)
 {
+  if(nbits == 0) {
+    return 0;
+  }
   size_t count = 0;
   size_t size = sizeof(uint32_t);
   size_t len = (nbits+7)/8;

+ 1 - 0
test/bitfieldTest.cc

@@ -45,6 +45,7 @@ void bitfieldTest::testCountSetBit()
   CPPUNIT_ASSERT_EQUAL((size_t)37, bitfield::countSetBit(bitfield, 48));
   CPPUNIT_ASSERT_EQUAL((size_t)36, bitfield::countSetBit(bitfield, 47));
   CPPUNIT_ASSERT_EQUAL((size_t)28, bitfield::countSetBit(bitfield, 32));
+  CPPUNIT_ASSERT_EQUAL((size_t)0, bitfield::countSetBit(bitfield, 0));
 }
 
 void bitfieldTest::testLastByteMask()