Просмотр исходного кода

2007-01-30 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

	To fix segfault in Metalink download:
	
	* src/UrlRequestInfo.h
	(filename): Removed.
	(totalLength): Removed.
	(setTotalLength): Removed.
	(setFilename): Removed.
	* src/MetalinkRequestInfo.cc
	(execute): Do not set filename and totalLength to reqInfo.
	Set chunk checksum to reqInfo if it is not null.
	
	* src/HttpResponseCommand.cc
	(executeInternal): Fixed filename in log.
	(handleDefaultEncoding): Removed the call to initBitfield() and
	markAllPiecesDone().
	(handleOtherEncoding): Added HEAD method handling.
	
	* src/FtpNegotiateCommand.cc
	(executeInternal): Added SEQ_HEAD_OK handling.
	(recvSize): In HEAD handling, set sequence to SEQ_HEAD_OK and
	return false.
	
	* src/FtpNegotiateCommand.h
	(SEQ_HEAD_OK): New definition.
	
	* src/SegmentMan.cc
	(initBitfield): Delete bitfield.
	(isChunkChecksumValidationReady): Fixed the condition.

	* src/UrlRequestInfo.cc: Fixed so that Metalink and Torrent 
download
	works fine.
Tatsuhiro Tsujikawa 18 лет назад
Родитель
Сommit
77a05c00b1

+ 34 - 0
ChangeLog

@@ -1,3 +1,37 @@
+2007-01-30  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	To fix segfault in Metalink download:
+	
+	* src/UrlRequestInfo.h
+	(filename): Removed.
+	(totalLength): Removed.
+	(setTotalLength): Removed.
+	(setFilename): Removed.
+	* src/MetalinkRequestInfo.cc
+	(execute): Do not set filename and totalLength to reqInfo.
+	Set chunk checksum to reqInfo if it is not null.
+	
+	* src/HttpResponseCommand.cc
+	(executeInternal): Fixed filename in log.
+	(handleDefaultEncoding): Removed the call to initBitfield() and
+	markAllPiecesDone().
+	(handleOtherEncoding): Added HEAD method handling.
+	
+	* src/FtpNegotiateCommand.cc
+	(executeInternal): Added SEQ_HEAD_OK handling.
+	(recvSize): In HEAD handling, set sequence to SEQ_HEAD_OK and
+	return false.
+	
+	* src/FtpNegotiateCommand.h
+	(SEQ_HEAD_OK): New definition.
+	
+	* src/SegmentMan.cc
+	(initBitfield): Delete bitfield.
+	(isChunkChecksumValidationReady): Fixed the condition.
+
+	* src/UrlRequestInfo.cc: Fixed so that Metalink and Torrent download
+	works fine.
+	
 2007-01-28  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
 
 	* src/Xml2MetalinkProcessor.h

+ 10 - 10
configure

@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.61 for aria2c 0.10.0.
+# Generated by GNU Autoconf 2.61 for aria2c 0.10.0+1.
 #
 # Report bugs to <t-tujikawa@users.sourceforge.net>.
 #
@@ -574,8 +574,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
 # Identity of this package.
 PACKAGE_NAME='aria2c'
 PACKAGE_TARNAME='aria2c'
-PACKAGE_VERSION='0.10.0'
-PACKAGE_STRING='aria2c 0.10.0'
+PACKAGE_VERSION='0.10.0+1'
+PACKAGE_STRING='aria2c 0.10.0+1'
 PACKAGE_BUGREPORT='t-tujikawa@users.sourceforge.net'
 
 ac_unique_file="src/Socket.h"
@@ -1275,7 +1275,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures aria2c 0.10.0 to adapt to many kinds of systems.
+\`configure' configures aria2c 0.10.0+1 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1345,7 +1345,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of aria2c 0.10.0:";;
+     short | recursive ) echo "Configuration of aria2c 0.10.0+1:";;
    esac
   cat <<\_ACEOF
 
@@ -1466,7 +1466,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-aria2c configure 0.10.0
+aria2c configure 0.10.0+1
 generated by GNU Autoconf 2.61
 
 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1480,7 +1480,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by aria2c $as_me 0.10.0, which was
+It was created by aria2c $as_me 0.10.0+1, which was
 generated by GNU Autoconf 2.61.  Invocation command line was
 
   $ $0 $@
@@ -2150,7 +2150,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='aria2c'
- VERSION='0.10.0'
+ VERSION='0.10.0+1'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -12941,7 +12941,7 @@ exec 6>&1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by aria2c $as_me 0.10.0, which was
+This file was extended by aria2c $as_me 0.10.0+1, which was
 generated by GNU Autoconf 2.61.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -12994,7 +12994,7 @@ Report bugs to <bug-autoconf@gnu.org>."
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-aria2c config.status 0.10.0
+aria2c config.status 0.10.0+1
 configured by $0, generated by GNU Autoconf 2.61,
   with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
 

+ 1 - 1
configure.ac

@@ -2,7 +2,7 @@
 # Process this file with autoconf to produce a configure script.
 #
 AC_PREREQ(2.59)
-AC_INIT(aria2c, 0.10.0, t-tujikawa@users.sourceforge.net)
+AC_INIT(aria2c, 0.10.0+1, t-tujikawa@users.sourceforge.net)
 AM_INIT_AUTOMAKE()
 AM_PATH_CPPUNIT(1.10.2)
 AC_CONFIG_SRCDIR([src/Socket.h])

+ 1 - 1
po/Makefile.in

@@ -9,7 +9,7 @@
 # General Public License and is *not* in the public domain.
 
 PACKAGE = aria2c
-VERSION = 0.10.0
+VERSION = 0.10.0+1
 
 SHELL = /bin/sh
 

+ 7 - 10
src/FtpNegotiationCommand.cc

@@ -67,6 +67,8 @@ bool FtpNegotiationCommand::executeInternal(Segment& segment) {
     command->setLowestDownloadSpeedLimit(e->option->getAsInt(PREF_LOWEST_SPEED_LIMIT));
     e->commands.push_back(command);
     return true;
+  } else if(sequence == SEQ_HEAD_OK) {
+    return true;
   } else {
     e->commands.push_back(this);
     return false;
@@ -186,21 +188,16 @@ bool FtpNegotiationCommand::recvSize() {
     throw new DlAbortEx(EX_TOO_LARGE_FILE, size);
   }
   if(!e->segmentMan->downloadStarted) {
-    if(req->getMethod() == Request::METHOD_HEAD) {
-      e->segmentMan->downloadStarted = true;
-      e->segmentMan->totalSize = size;
-      e->segmentMan->initBitfield(e->option->getAsInt(PREF_SEGMENT_SIZE),
-				  e->segmentMan->totalSize);
-      e->segmentMan->markAllPiecesDone();
-      e->segmentMan->isSplittable = false; // TODO because we don't want segment file to be saved.
-      return true;
-    }
     e->segmentMan->downloadStarted = true;
     e->segmentMan->totalSize = size;
     e->segmentMan->initBitfield(e->option->getAsInt(PREF_SEGMENT_SIZE),
 				e->segmentMan->totalSize);
-
     e->segmentMan->filename = Util::urldecode(req->getFile());
+    if(req->getMethod() == Request::METHOD_HEAD) {
+      e->segmentMan->isSplittable = false; // TODO because we don't want segment file to be saved.
+      sequence = SEQ_HEAD_OK;
+      return false;
+    }
     bool segFileExists = e->segmentMan->segmentFileExists();
     if(segFileExists) {
       e->segmentMan->load();

+ 2 - 1
src/FtpNegotiationCommand.h

@@ -62,7 +62,8 @@ private:
     SEQ_SEND_RETR,
     SEQ_RECV_RETR,
     SEQ_NEGOTIATION_COMPLETED,
-    SEQ_RETRY
+    SEQ_RETRY,
+    SEQ_HEAD_OK
   };
   bool recvGreeting();
   bool sendUser();

+ 13 - 5
src/HttpResponseCommand.cc

@@ -91,8 +91,11 @@ bool HttpResponseCommand::executeInternal(Segment& segment) {
       return handleDefaultEncoding(headers);
     }
   } else {
-    if(determinFilename(headers) != e->segmentMan->filename) {
-      throw new DlAbortEx(EX_FILENAME_MISMATCH, req->getFile().c_str(), e->segmentMan->filename.c_str());
+    string filenameInHeader = determinFilename(headers);
+    if(filenameInHeader != e->segmentMan->filename) {
+      throw new DlAbortEx(EX_FILENAME_MISMATCH,
+			  filenameInHeader.c_str(),
+			  e->segmentMan->filename.c_str());
     }
     createHttpDownloadCommand();
     return true;
@@ -158,9 +161,6 @@ bool HttpResponseCommand::handleDefaultEncoding(const HttpHeader& headers) {
   if(req->getMethod() == Request::METHOD_HEAD) {
     e->segmentMan->downloadStarted = true;
     e->segmentMan->totalSize = size;
-    e->segmentMan->initBitfield(e->option->getAsInt(PREF_SEGMENT_SIZE),
-				e->segmentMan->totalSize);
-    e->segmentMan->markAllPiecesDone();
     e->segmentMan->isSplittable = false; // TODO because we don't want segment file to be saved.
     return true;
   }
@@ -182,6 +182,14 @@ bool HttpResponseCommand::handleDefaultEncoding(const HttpHeader& headers) {
 }
 
 bool HttpResponseCommand::handleOtherEncoding(const string& transferEncoding, const HttpHeader& headers) {
+  // quick hack for method 'head'
+  if(req->getMethod() == Request::METHOD_HEAD) {
+    e->segmentMan->downloadStarted = true;
+    e->segmentMan->isSplittable = false;
+    e->segmentMan->filename = determinFilename(headers);
+    e->segmentMan->totalSize = 0;
+    return true;
+  }
   if(e->segmentMan->shouldCancelDownloadForSafety()) {
     throw new FatalException(EX_FILE_ALREADY_EXISTS,
 			     e->segmentMan->getFilePath().c_str(),

+ 5 - 5
src/MetalinkRequestInfo.cc

@@ -122,13 +122,13 @@ RequestInfos MetalinkRequestInfo::execute() {
 	urls.push_back((*itr)->url);
       }
       UrlRequestInfoHandle reqInfo = new UrlRequestInfo(urls, maxConnection, op);
-      reqInfo->setFilename(entry->filename);
-      reqInfo->setTotalLength(entry->size);
 #ifdef ENABLE_MESSAGE_DIGEST
       reqInfo->setChecksum(checksum);
-      reqInfo->setDigestAlgo(entry->chunkChecksum->digestAlgo);
-      reqInfo->setChunkChecksumLength(entry->chunkChecksum->pieceLength);
-      reqInfo->setChunkChecksums(entry->chunkChecksum->pieceHashes);
+      if(!entry->chunkChecksum.isNull()) {
+	reqInfo->setDigestAlgo(entry->chunkChecksum->digestAlgo);
+	reqInfo->setChunkChecksumLength(entry->chunkChecksum->pieceLength);
+	reqInfo->setChunkChecksums(entry->chunkChecksum->pieceHashes);
+      }
 #endif // ENABLE_MESSAGE_DIGEST
       nextReqInfos.push_front(reqInfo);
     }

+ 3 - 2
src/SegmentMan.cc

@@ -237,6 +237,7 @@ void SegmentMan::init() {
 }
 
 void SegmentMan::initBitfield(int segmentLength, long long int totalLength) {
+  delete bitfield;
   this->bitfield = BitfieldManFactory::getNewFactory()->createBitfieldMan(segmentLength, totalLength);
 }
 
@@ -479,8 +480,8 @@ void SegmentMan::checkIntegrity()
 
 #ifdef ENABLE_MESSAGE_DIGEST
 bool SegmentMan::isChunkChecksumValidationReady() const {
-  return bitfield &&
-    ((int64_t)pieceHashes.size())*chunkHashLength == ((int64_t)bitfield->getBlockLength())*(bitfield->getMaxIndex()+1);
+  return bitfield && totalSize > 0 &&
+    ((int64_t)pieceHashes.size())*chunkHashLength >= totalSize;
 }
 #endif // ENABLE_MESSAGE_DIGEST
 

+ 39 - 30
src/UrlRequestInfo.cc

@@ -127,6 +127,10 @@ HeadResult UrlRequestInfo::getHeadResult() {
 			 op->get(PREF_REFERER),
 			 1,
 			 Request::METHOD_HEAD));
+  if(requests.size() == 0) {
+    fail = true;
+    return HeadResult();
+  }
   Requests reserved(requests.begin()+1, requests.end());
   requests.erase(requests.begin()+1, requests.end());
 
@@ -135,8 +139,12 @@ HeadResult UrlRequestInfo::getHeadResult() {
   HeadResult hr;
   try {
     e->run();
-    hr.filename = e->segmentMan->filename;
-    hr.totalLength = e->segmentMan->totalSize;
+    if(e->segmentMan->errors > 0) {
+      fail = true;
+    } else {
+      hr.filename = e->segmentMan->filename;
+      hr.totalLength = e->segmentMan->totalSize;
+    }
   } catch(RecoverableException *ex) {
     logger->error("Exception caught", ex);
     delete ex;
@@ -150,34 +158,33 @@ RequestInfos UrlRequestInfo::execute() {
   Requests requests;
   Requests reserved;
   printUrls(urls);
+  HeadResult hr = getHeadResult();
+  if(fail) {
+    return RequestInfos();
+  }
+
   for_each(urls.begin(), urls.end(),
 	   CreateRequest(&requests,
 			 op->get(PREF_REFERER),
 			 op->getAsInt(PREF_SPLIT)));
+  
+  logger->info("Head result: filename=%s, total length=%s",
+	       hr.filename.c_str(), Util::ullitos(hr.totalLength, true).c_str());
 
-  HeadResult hr;
-  if(filename.size() && totalLength > 0) {
-    hr.filename = filename;
-    hr.totalLength = totalLength;
-  } else {
-    hr = getHeadResult();
-    if(fail) {
-      return RequestInfos();
-    }
-    
-    logger->info("Head result: filename=%s, total length=%s",
-		 hr.filename.c_str(), Util::ullitos(hr.totalLength, true).c_str());
-  }
   adjustRequestSize(requests, reserved, maxConnections);
   
   SharedHandle<ConsoleDownloadEngine> e(DownloadEngineFactory::newConsoleEngine(op, requests, reserved));
-  e->segmentMan->filename = hr.filename;
-  e->segmentMan->totalSize = hr.totalLength;
-  e->segmentMan->downloadStarted = true;
+  if(hr.totalLength > 0) {
+    e->segmentMan->filename = hr.filename;
+    e->segmentMan->totalSize = hr.totalLength;
+    e->segmentMan->downloadStarted = true;
+  }
 #ifdef ENABLE_MESSAGE_DIGEST
-  e->segmentMan->digestAlgo = digestAlgo;
-  e->segmentMan->chunkHashLength = chunkChecksumLength;
-  e->segmentMan->pieceHashes = chunkChecksums;
+  if(chunkChecksumLength > 0) {
+    e->segmentMan->digestAlgo = digestAlgo;
+    e->segmentMan->chunkHashLength = chunkChecksumLength;
+    e->segmentMan->pieceHashes = chunkChecksums;
+  }
 #endif // ENABLE_MESSAGE_DIGEST
 
   if(e->segmentMan->segmentFileExists()) {
@@ -194,17 +201,19 @@ RequestInfos UrlRequestInfo::execute() {
 			       e->segmentMan->getFilePath().c_str(),
 			       e->segmentMan->getSegmentFilePath().c_str());
     }
-    e->segmentMan->initBitfield(e->option->getAsInt(PREF_SEGMENT_SIZE),
-				e->segmentMan->totalSize);
-    if(e->segmentMan->fileExists() && e->option->get(PREF_CHECK_INTEGRITY) == V_TRUE) {
-      e->segmentMan->diskWriter->openExistingFile(e->segmentMan->getFilePath());
+    if(e->segmentMan->totalSize > 0) {
+      e->segmentMan->initBitfield(e->option->getAsInt(PREF_SEGMENT_SIZE),
+				  e->segmentMan->totalSize);
+      if(e->segmentMan->fileExists() && e->option->get(PREF_CHECK_INTEGRITY) == V_TRUE) {
+	e->segmentMan->diskWriter->openExistingFile(e->segmentMan->getFilePath());
 #ifdef ENABLE_MESSAGE_DIGEST
-      e->segmentMan->markAllPiecesDone();
-      e->segmentMan->checkIntegrity();
+	e->segmentMan->markAllPiecesDone();
+	e->segmentMan->checkIntegrity();
 #endif // ENABLE_MESSAGE_DIGEST
-    } else {
-      e->segmentMan->diskWriter->initAndOpenFile(e->segmentMan->getFilePath(),
-						 e->segmentMan->totalSize);
+      } else {
+	e->segmentMan->diskWriter->initAndOpenFile(e->segmentMan->getFilePath(),
+						   e->segmentMan->totalSize);
+      }
     }
   }
   Util::setGlobalSignalHandler(SIGINT, handler, 0);

+ 6 - 14
src/UrlRequestInfo.h

@@ -39,9 +39,10 @@
 
 class HeadResult {
 public:
-  HeadResult():totalLength(0) {}
   string filename;
   int64_t totalLength;
+public:
+  HeadResult():totalLength(0) {}
 };
 
 std::ostream& operator<<(std::ostream& o, const HeadResult& hr);
@@ -55,8 +56,6 @@ private:
   int32_t chunkChecksumLength;
   Strings chunkChecksums;
 #endif // ENABLE_MESSAGE_DIGEST
-  string filename;
-  int64_t totalLength;
 
   RequestInfo* createNextRequestInfo() const;
   void adjustRequestSize(Requests& requests,
@@ -68,12 +67,13 @@ public:
   UrlRequestInfo(const Strings& urls, int maxConnections, Option* op):
     RequestInfo(op),
     urls(urls),
-    maxConnections(maxConnections),
+    maxConnections(maxConnections)
 #ifdef ENABLE_MESSAGE_DIGEST
+    ,
     digestAlgo(DIGEST_ALGO_SHA1),
-    chunkChecksumLength(0),
+    chunkChecksumLength(0)
 #endif // ENABLE_MESSAGE_DIGEST
-    totalLength(0) {}
+    {}
 
   virtual ~UrlRequestInfo() {}
 
@@ -96,14 +96,6 @@ public:
     this->chunkChecksums = chunkChecksums;
   }
 #endif // ENABLE_MESSAGE_DIGEST
-
-  void setTotalLength(int64_t totalLength) {
-    this->totalLength = totalLength;
-  }
-
-  void setFilename(const string& filename) {
-    this->filename = filename;
-  }
 };
 
 typedef SharedHandle<UrlRequestInfo> UrlRequestInfoHandle;