Explorar o código

Added more error code values.

I have not set error code for all exception invocation.
In this change, I set error code where error likely occurs.
Tatsuhiro Tsujikawa %!s(int64=15) %!d(string=hai) anos
pai
achega
f0f4f8f703

+ 6 - 4
src/AbstractCommand.cc

@@ -65,6 +65,7 @@
 #include "NameResolver.h"
 #include "uri.h"
 #include "FileEntry.h"
+#include "error_code.h"
 #ifdef ENABLE_ASYNC_DNS
 #include "AsyncNameResolver.h"
 #endif // ENABLE_ASYNC_DNS
@@ -650,11 +651,12 @@ bool AbstractCommand::asyncResolveHostname()
       e_->getRequestGroupMan()->getOrCreateServerStat
         (req_->getHost(), req_->getProtocol())->setError();
     }
-    throw DL_ABORT_EX
+    throw DL_ABORT_EX2
       (fmt(MSG_NAME_RESOLUTION_FAILED,
-                    getCuid(),
-                    asyncNameResolver_->getHostname().c_str(),
-                    asyncNameResolver_->getError().c_str()));
+           getCuid(),
+           asyncNameResolver_->getHostname().c_str(),
+           asyncNameResolver_->getError().c_str()),
+       error_code::NAME_RESOLVE_ERROR);
   default:
     return false;
   }

+ 45 - 27
src/AbstractDiskWriter.cc

@@ -51,6 +51,7 @@
 #include "a2io.h"
 #include "fmt.h"
 #include "DownloadFailureException.h"
+#include "error_code.h"
 
 namespace aria2 {
 
@@ -100,10 +101,12 @@ void AbstractDiskWriter::openExistingFile(uint64_t totalLength)
         errno == EINTR);
   if(fd_ < 0) {
     int errNum = errno;
-    throw DL_ABORT_EX2
-      (errNum, fmt(EX_FILE_OPEN,
-                   filename_.c_str(),
-                   util::safeStrerror(errNum).c_str()));
+    throw DL_ABORT_EX3
+      (errNum,
+       fmt(EX_FILE_OPEN,
+           filename_.c_str(),
+           util::safeStrerror(errNum).c_str()),
+       error_code::FILE_OPEN_ERROR);
   }
 }
 
@@ -116,10 +119,12 @@ void AbstractDiskWriter::createFile(int addFlags)
                     OPEN_MODE)) == -1 && errno == EINTR);
   if(fd_ < 0) {
     int errNum = errno;
-    throw DL_ABORT_EX2
-      (errNum, fmt(EX_FILE_OPEN,
-                   filename_.c_str(),
-                   util::safeStrerror(errNum).c_str()));
+    throw DL_ABORT_EX3
+      (errNum,
+       fmt(EX_FILE_OPEN,
+           filename_.c_str(),
+           util::safeStrerror(errNum).c_str()),
+       error_code::FILE_CREATE_ERROR);
   }  
 }
 
@@ -148,9 +153,10 @@ void AbstractDiskWriter::seek(off_t offset)
 {
   if(a2lseek(fd_, offset, SEEK_SET) == (off_t)-1) {
     int errNum = errno;
-    throw DL_ABORT_EX(fmt(EX_FILE_SEEK,
-                          filename_.c_str(),
-                          util::safeStrerror(errNum).c_str()));
+    throw DL_ABORT_EX2(fmt(EX_FILE_SEEK,
+                           filename_.c_str(),
+                           util::safeStrerror(errNum).c_str()),
+                       error_code::FILE_IO_ERROR);
   }
 }
 
@@ -162,16 +168,19 @@ void AbstractDiskWriter::writeData(const unsigned char* data, size_t len, off_t
     // If errno is ENOSPC(not enough space in device), throw
     // DownloadFailureException and abort download instantly.
     if(errNum == ENOSPC) {
-      throw DOWNLOAD_FAILURE_EXCEPTION2
-        (fmt(EX_FILE_WRITE,
+      throw DOWNLOAD_FAILURE_EXCEPTION3
+        (errNum,
+         fmt(EX_FILE_WRITE,
              filename_.c_str(),
              util::safeStrerror(errNum).c_str()),
          error_code::NOT_ENOUGH_DISK_SPACE);
     } else {
-      throw DL_ABORT_EX
-        (fmt(EX_FILE_WRITE,
+      throw DL_ABORT_EX3
+        (errNum,
+         fmt(EX_FILE_WRITE,
              filename_.c_str(),
-             util::safeStrerror(errNum).c_str()));
+             util::safeStrerror(errNum).c_str()),
+         error_code::FILE_IO_ERROR);
     }
   }
 }
@@ -182,10 +191,12 @@ ssize_t AbstractDiskWriter::readData(unsigned char* data, size_t len, off_t offs
   seek(offset);
   if((ret = readDataInternal(data, len)) < 0) {
     int errNum = errno;
-    throw DL_ABORT_EX
-      (fmt(EX_FILE_READ,
+    throw DL_ABORT_EX3
+      (errNum,
+       fmt(EX_FILE_READ,
            filename_.c_str(),
-           util::safeStrerror(errNum).c_str()));
+           util::safeStrerror(errNum).c_str()),
+       error_code::FILE_IO_ERROR);
   }
   return ret;
 }
@@ -201,14 +212,17 @@ void AbstractDiskWriter::truncate(uint64_t length)
   HANDLE handle = LongToHandle(_get_osfhandle(fd_));
   seek(length);
   if(SetEndOfFile(handle) == 0) {
-    throw DL_ABORT_EX(fmt("SetEndOfFile failed. cause: %s",
-                          GetLastError()));
+    throw DL_ABORT_EX2(fmt("SetEndOfFile failed. cause: %s",
+                           GetLastError()),
+                       error_code::FILE_IO_ERROR);
   }
 #else
   if(ftruncate(fd_, length) == -1) {
     int errNum = errno;
-    throw DL_ABORT_EX(fmt("ftruncate failed. cause: %s",
-                          util::safeStrerror(errNum).c_str()));
+    throw DL_ABORT_EX3(errNum,
+                       fmt("ftruncate failed. cause: %s",
+                           util::safeStrerror(errNum).c_str()),
+                       error_code::FILE_IO_ERROR);
   }
 #endif
 }
@@ -226,14 +240,18 @@ void AbstractDiskWriter::allocate(off_t offset, uint64_t length)
   while((r = fallocate(fd_, 0, offset, length)) == -1 && errno == EINTR);
   int errNum = errno;
   if(r == -1) {
-    throw DL_ABORT_EX(fmt("fallocate failed. cause: %s",
-                          util::safeStrerror(errNum).c_str()));
+    throw DL_ABORT_EX3(errNum,
+                       fmt("fallocate failed. cause: %s",
+                           util::safeStrerror(errNum).c_str()),
+                       error_code::FILE_IO_ERROR);
   }
 # elif HAVE_POSIX_FALLOCATE
   int r = posix_fallocate(fd_, offset, length);
   if(r != 0) {
-    throw DL_ABORT_EX(fmt("posix_fallocate failed. cause: %s",
-                          util::safeStrerror(r).c_str()));
+    throw DL_ABORT_EX3(errNum,
+                       fmt("posix_fallocate failed. cause: %s",
+                           util::safeStrerror(r).c_str()),
+                       error_code::FILE_IO_ERROR);
   }
 # else
 #  error "no *_fallocate function available."

+ 1 - 1
src/DlAbortEx.h

@@ -58,7 +58,7 @@ public:
 
 #define DL_ABORT_EX(arg) DlAbortEx(__FILE__, __LINE__, arg)
 #define DL_ABORT_EX2(arg1, arg2) DlAbortEx(__FILE__, __LINE__, arg1, arg2)
-#define DL_ABORT_EX3(arg1, arg2, arg3)\
+#define DL_ABORT_EX3(arg1, arg2, arg3)                  \
   DlAbortEx(__FILE__, __LINE__, arg1, arg2, arg3)
 
 } // namespace aria2

+ 7 - 0
src/DownloadFailureException.cc

@@ -57,4 +57,11 @@ DownloadFailureException::DownloadFailureException
  error_code::Value code):
   RecoverableException(file, line, msg, code) {}
 
+DownloadFailureException::DownloadFailureException
+(const char* file, int line,
+ int errNum,
+ const std::string& msg,
+ error_code::Value code):
+  RecoverableException(file, line, errNum, msg, code) {}
+
 } // namespace aria2

+ 7 - 0
src/DownloadFailureException.h

@@ -54,12 +54,19 @@ public:
   DownloadFailureException(const char* file, int line,
                            const std::string& msg,
                            error_code::Value code);
+
+  DownloadFailureException(const char* file, int line,
+                           int errNum,
+                           const std::string& msg,
+                           error_code::Value code);
 };
 
 #define DOWNLOAD_FAILURE_EXCEPTION(arg)                 \
   DownloadFailureException(__FILE__, __LINE__, arg)
 #define DOWNLOAD_FAILURE_EXCEPTION2(arg1, arg2)                 \
   DownloadFailureException(__FILE__, __LINE__, arg1, arg2)
+#define DOWNLOAD_FAILURE_EXCEPTION3(arg1, arg2, arg3)                   \
+  DownloadFailureException(__FILE__, __LINE__, arg1, arg2, arg3)
 
 } // namespace aria2
 

+ 16 - 2
src/Exception.cc

@@ -53,13 +53,27 @@ Exception::Exception
 (const char* file,
  int line,
  const std::string& msg,
+ error_code::Value errorCode,
  const Exception& cause)
   : file_(file),
     line_(line),
     errNum_(0),
     msg_(msg),
-    cause_(cause.copy()),
-    errorCode_(cause.errorCode_)
+    errorCode_(errorCode),
+    cause_(cause.copy())
+{}
+
+Exception::Exception
+(const char* file,
+ int line,
+ const std::string& msg,
+ const Exception& cause)
+  : file_(file),
+    line_(line),
+    errNum_(0),
+    msg_(msg),
+    errorCode_(cause.errorCode_),
+    cause_(cause.copy())
 {}
 
 Exception::Exception

+ 6 - 2
src/Exception.h

@@ -53,16 +53,20 @@ private:
   int errNum_;
 
   std::string msg_;
+  // This is application-level error code.
+  error_code::Value errorCode_;
   // Exception that this object wraps. Normally this cause_ is the
   // root cause of this exception.
   SharedHandle<Exception> cause_;
-  // This is application-level error code.
-  error_code::Value errorCode_;
 protected:
   virtual SharedHandle<Exception> copy() const = 0;
 
 public:
   Exception(const char* file, int line, const std::string& msg);
+
+  Exception(const char* file, int line, const std::string& msg,
+            error_code::Value errorCode,
+            const Exception& cause);
   // errorCode_ is initializedwith cause.errorCode_.
   Exception(const char* file, int line, const std::string& msg,
             const Exception& cause);

+ 13 - 6
src/ExpatMetalinkProcessor.cc

@@ -46,6 +46,7 @@
 #include "DlAbortEx.h"
 #include "MetalinkParserState.h"
 #include "A2STR.h"
+#include "error_code.h"
 
 namespace aria2 {
 
@@ -158,16 +159,19 @@ namespace {
 void checkError(XML_Parser parser)
 {
   if(XML_Parse(parser, 0, 0, 1) == XML_STATUS_ERROR) {
-    throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK);
+    throw DL_ABORT_EX2(MSG_CANNOT_PARSE_METALINK,
+                       error_code::METALINK_PARSE_ERROR);
   }
   SessionData* sessionData =
     reinterpret_cast<SessionData*>(XML_GetUserData(parser));
   const SharedHandle<MetalinkParserStateMachine>& stm = sessionData->stm_;
   if(!stm->finished()) {
-    throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK);
+    throw DL_ABORT_EX2(MSG_CANNOT_PARSE_METALINK,
+                       error_code::METALINK_PARSE_ERROR);
   }
   if(!stm->getErrors().empty()) {
-    throw DL_ABORT_EX(stm->getErrorString());
+    throw DL_ABORT_EX2(stm->getErrorString(),
+                       error_code::METALINK_PARSE_ERROR);
   }
 }
 } // namespace
@@ -195,11 +199,13 @@ MetalinkProcessor::parseFile(std::istream& stream)
   while(stream) {
     stream.read(buf, sizeof(buf));
     if(XML_Parse(parser, buf, stream.gcount(), 0) == XML_STATUS_ERROR) {
-      throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK);
+      throw DL_ABORT_EX2(MSG_CANNOT_PARSE_METALINK,
+                         error_code::METALINK_PARSE_ERROR);
     }
   }
   if(stream.bad()) {
-    throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK);
+    throw DL_ABORT_EX2(MSG_CANNOT_PARSE_METALINK,
+                       error_code::METALINK_PARSE_ERROR);
   }
   checkError(parser);
   return stm_->getResult();
@@ -223,7 +229,8 @@ MetalinkProcessor::parseFromBinaryStream(const SharedHandle<BinaryStream>& binar
     }
     if(XML_Parse(parser, reinterpret_cast<const char*>(buf), res, 0) ==
        XML_STATUS_ERROR) {
-      throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK);
+      throw DL_ABORT_EX2(MSG_CANNOT_PARSE_METALINK,
+                         error_code::METALINK_PARSE_ERROR);
     }
     readOffset += res;
   }

+ 5 - 2
src/FtpConnection.cc

@@ -56,6 +56,7 @@
 #include "AuthConfig.h"
 #include "a2functional.h"
 #include "util.h"
+#include "error_code.h"
 
 namespace aria2 {
 
@@ -382,7 +383,8 @@ bool FtpConnection::bulkReceiveResponse
   if(strbuf_.size() >= 4) {
     status = getStatus(strbuf_);
     if(status == 0) {
-      throw DL_ABORT_EX(EX_INVALID_RESPONSE);
+      throw DL_ABORT_EX2(EX_INVALID_RESPONSE,
+                         error_code::FTP_PROTOCOL_ERROR);
     }
   } else {
     return false;
@@ -549,7 +551,8 @@ unsigned int FtpConnection::receivePwdResponse(std::string& pwd)
          (last = response.second.find("\"", ++first)) != std::string::npos) {
         pwd = response.second.substr(first, last-first);
       } else {
-        throw DL_ABORT_EX(EX_INVALID_RESPONSE);
+        throw DL_ABORT_EX2(EX_INVALID_RESPONSE,
+                           error_code::FTP_PROTOCOL_ERROR);
       }
     }
     return response.first;

+ 24 - 13
src/FtpNegotiationCommand.cc

@@ -72,6 +72,7 @@
 #include "HttpResponse.h"
 #include "DlRetryEx.h"
 #include "CheckIntegrityEntry.h"
+#include "error_code.h"
 
 namespace aria2 {
 
@@ -154,7 +155,7 @@ bool FtpNegotiationCommand::recvGreeting() {
     return false;
   }
   if(status != 220) {
-    throw DL_ABORT_EX(EX_CONNECTION_FAILED);
+    throw DL_ABORT_EX2(EX_CONNECTION_FAILED, error_code::FTP_PROTOCOL_ERROR);
   }
   sequence_ = SEQ_SEND_USER;
 
@@ -183,7 +184,8 @@ bool FtpNegotiationCommand::recvUser() {
     sequence_ = SEQ_SEND_PASS;
     break;
   default:
-    throw DL_ABORT_EX(fmt(EX_BAD_STATUS, status));
+    throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, status),
+                       error_code::FTP_PROTOCOL_ERROR);
   }
   return true;
 }
@@ -204,7 +206,8 @@ bool FtpNegotiationCommand::recvPass() {
     return false;
   }
   if(status != 230) {
-    throw DL_ABORT_EX(fmt(EX_BAD_STATUS, status));
+    throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, status),
+                       error_code::FTP_PROTOCOL_ERROR);
   }
   sequence_ = SEQ_SEND_TYPE;
   return true;
@@ -226,7 +229,8 @@ bool FtpNegotiationCommand::recvType() {
     return false;
   }
   if(status != 200) {
-    throw DL_ABORT_EX(fmt(EX_BAD_STATUS, status));
+    throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, status),
+                       error_code::FTP_PROTOCOL_ERROR);
   }
   sequence_ = SEQ_SEND_PWD;
   return true;
@@ -251,7 +255,8 @@ bool FtpNegotiationCommand::recvPwd()
     return false;
   }
   if(status != 257) {
-    throw DL_ABORT_EX(fmt(EX_BAD_STATUS, status));
+    throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, status),
+                       error_code::FTP_PROTOCOL_ERROR);
   }
   ftp_->setBaseWorkingDir(pwd);
   A2_LOG_INFO(fmt("CUID#%lld - base working directory is '%s'",
@@ -295,7 +300,8 @@ bool FtpNegotiationCommand::recvCwd()
       throw DL_ABORT_EX2(MSG_RESOURCE_NOT_FOUND,
                          error_code::RESOURCE_NOT_FOUND);
     else
-      throw DL_ABORT_EX(fmt(EX_BAD_STATUS, status));
+      throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, status),
+                         error_code::FTP_PROTOCOL_ERROR);
   }
   cwdDirs_.pop_front();
   if(cwdDirs_.empty()) {
@@ -461,9 +467,10 @@ bool FtpNegotiationCommand::recvSize() {
   if(status == 213) {
 
     if(size > INT64_MAX) {
-      throw DL_ABORT_EX
+      throw DL_ABORT_EX2
         (fmt(EX_TOO_LARGE_FILE,
-             util::uitos(size, true).c_str()));
+             util::uitos(size, true).c_str()),
+         error_code::FTP_PROTOCOL_ERROR);
     }
     if(!getPieceStorage()) {
 
@@ -563,7 +570,8 @@ bool FtpNegotiationCommand::recvPort() {
     return false;
   }
   if(status != 200) {
-    throw DL_ABORT_EX(fmt(EX_BAD_STATUS, status));
+    throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, status),
+                       error_code::FTP_PROTOCOL_ERROR);
   }
   sequence_ = SEQ_SEND_REST;
   return true;
@@ -624,7 +632,8 @@ bool FtpNegotiationCommand::recvPasv() {
     return false;
   }
   if(status != 227) {
-    throw DL_ABORT_EX(fmt(EX_BAD_STATUS, status));
+    throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, status),
+                       error_code::FTP_PROTOCOL_ERROR);
   }
   dataConnAddr_ = dest;
 
@@ -744,8 +753,9 @@ bool FtpNegotiationCommand::sendRestPasv(const SharedHandle<Segment>& segment) {
   // Check connection is made properly
   if(dataSocket_->isReadable(0)) {
     std::string error = dataSocket_->getSocketError();
-    throw DL_ABORT_EX
-      (fmt(MSG_ESTABLISHING_CONNECTION_FAILED, error.c_str()));
+    throw DL_ABORT_EX2
+      (fmt(MSG_ESTABLISHING_CONNECTION_FAILED, error.c_str()),
+       error_code::FTP_PROTOCOL_ERROR);
   }
   setReadCheckSocket(getSocket());
   disableWriteCheckSocket();
@@ -800,7 +810,8 @@ bool FtpNegotiationCommand::recvRetr() {
       throw DL_ABORT_EX2(MSG_RESOURCE_NOT_FOUND,
                          error_code::RESOURCE_NOT_FOUND);
     else
-      throw DL_ABORT_EX(fmt(EX_BAD_STATUS, status));
+      throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, status),
+                         error_code::FTP_PROTOCOL_ERROR);
   }
   if(getOption()->getAsBool(PREF_FTP_PASV)) {
     sequence_ = SEQ_NEGOTIATION_COMPLETED;

+ 5 - 2
src/HttpHeaderProcessor.cc

@@ -43,6 +43,7 @@
 #include "DlRetryEx.h"
 #include "DlAbortEx.h"
 #include "A2STR.h"
+#include "error_code.h"
 
 namespace aria2 {
 
@@ -71,7 +72,8 @@ void HttpHeaderProcessor::update(const std::string& data)
 void HttpHeaderProcessor::checkHeaderLimit(size_t incomingLength)
 {
   if(buf_.size()+incomingLength > limit_) {
-    throw DL_ABORT_EX("Too large http header");
+    throw DL_ABORT_EX2("Too large http header",
+                       error_code::HTTP_PROTOCOL_ERROR);
   }
 }
 
@@ -138,7 +140,8 @@ SharedHandle<HttpHeader> HttpHeaderProcessor::getHttpRequestHeader()
   std::vector<std::string> firstLine;
   util::split(buf_.substr(0, delimpos), std::back_inserter(firstLine)," ",true);
   if(firstLine.size() != 3) {
-    throw DL_ABORT_EX("Malformed HTTP request header.");    
+    throw DL_ABORT_EX2("Malformed HTTP request header.",
+                       error_code::HTTP_PROTOCOL_ERROR);
   }
   SharedHandle<HttpHeader> httpHeader(new HttpHeader());
   httpHeader->setMethod(firstLine[0]);

+ 7 - 3
src/HttpResponse.cc

@@ -50,6 +50,7 @@
 #include "AuthConfigFactory.h"
 #include "AuthConfig.h"
 #include "ChunkedDecodingStreamFilter.h"
+#include "error_code.h"
 #ifdef HAVE_LIBZ
 # include "GZipDecodingStreamFilter.h"
 #endif // HAVE_LIBZ
@@ -70,14 +71,16 @@ void HttpResponse::validateResponse() const
   }
   if(statusCode == 304) {
     if(httpRequest_->getIfModifiedSinceHeader().empty()) {
-      throw DL_ABORT_EX("Got 304 without If-Modified-Since");
+      throw DL_ABORT_EX2("Got 304 without If-Modified-Since",
+                         error_code::HTTP_PROTOCOL_ERROR);
     }
   } else if(statusCode == 301 ||
             statusCode == 302 ||
             statusCode == 303 ||
             statusCode == 307) {
     if(!httpHeader_->defined(HttpHeader::LOCATION)) {
-      throw DL_ABORT_EX(fmt(EX_LOCATION_HEADER_REQUIRED, statusCode));
+      throw DL_ABORT_EX2(fmt(EX_LOCATION_HEADER_REQUIRED, statusCode),
+                         error_code::HTTP_PROTOCOL_ERROR);
     }
     return;
   } else if(statusCode == 200 || statusCode == 206) {
@@ -97,7 +100,8 @@ void HttpResponse::validateResponse() const
       }
     }
   } else {
-    throw DL_ABORT_EX(fmt("Unexpected status %d", statusCode));
+    throw DL_ABORT_EX2(fmt("Unexpected status %d", statusCode),
+                       error_code::HTTP_PROTOCOL_ERROR);
   }
 }
 

+ 7 - 3
src/HttpSkipResponseCommand.cc

@@ -58,6 +58,7 @@
 #include "BinaryStream.h"
 #include "NullSinkStreamFilter.h"
 #include "SinkStreamFilter.h"
+#include "error_code.h"
 
 namespace aria2 {
 
@@ -175,7 +176,8 @@ bool HttpSkipResponseCommand::processResponse()
     unsigned int rnum =
       httpResponse_->getHttpRequest()->getRequest()->getRedirectCount();
     if(rnum >= Request::MAX_REDIRECT) {
-      throw DL_ABORT_EX(fmt("Too many redirects: count=%u", rnum));
+      throw DL_ABORT_EX2(fmt("Too many redirects: count=%u", rnum),
+                         error_code::HTTP_TOO_MANY_REDIRECTS);
     }
     httpResponse_->processRedirect();
     return prepareForRetry(0);
@@ -187,13 +189,15 @@ bool HttpSkipResponseCommand::processResponse()
          (getRequest()->getHost(), getRequest()->getDir(), getOption().get())) {
         return prepareForRetry(0);
       } else {
-        throw DL_ABORT_EX(EX_AUTH_FAILED);
+        throw DL_ABORT_EX2(EX_AUTH_FAILED,
+                           error_code::HTTP_AUTH_FAILED);
       }
     } else if(statusCode == 404) {
       throw DL_ABORT_EX2(MSG_RESOURCE_NOT_FOUND,
                          error_code::RESOURCE_NOT_FOUND);
     } else {
-      throw DL_ABORT_EX(fmt(EX_BAD_STATUS, statusCode));
+      throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, statusCode),
+                         error_code::HTTP_PROTOCOL_ERROR);
     }
   } else {
     return prepareForRetry(0);

+ 4 - 2
src/NameResolver.cc

@@ -41,6 +41,7 @@
 #include "fmt.h"
 #include "util.h"
 #include "SocketCore.h"
+#include "error_code.h"
 
 namespace aria2 {
 
@@ -53,8 +54,9 @@ void NameResolver::resolve(std::vector<std::string>& resolvedAddresses,
   int s;
   s = callGetaddrinfo(&res, hostname.c_str(), 0, family_, socktype_, 0, 0);
   if(s) {
-    throw DL_ABORT_EX(fmt(EX_RESOLVE_HOSTNAME,
-                          hostname.c_str(), gai_strerror(s)));
+    throw DL_ABORT_EX2(fmt(EX_RESOLVE_HOSTNAME,
+                           hostname.c_str(), gai_strerror(s)),
+                       error_code::NAME_RESOLVE_ERROR);
   }
   WSAAPI_AUTO_DELETE<struct addrinfo*> resDeleter(res, freeaddrinfo);
   struct addrinfo* rp;

+ 3 - 2
src/OptionHandlerException.cc

@@ -43,14 +43,15 @@ const std::string OptionHandlerException::MESSAGE
 OptionHandlerException::OptionHandlerException(const char* file, int line,
                                                const std::string& optName):
   RecoverableException
-  (file, line, fmt(MESSAGE.c_str(), optName.c_str())),
+  (file, line, fmt(MESSAGE.c_str(), optName.c_str()), error_code::OPTION_ERROR),
   optName_(optName) {}
 
 OptionHandlerException::OptionHandlerException(const char* file, int line,
                                                const std::string& optName,
                                                const Exception& cause):
   RecoverableException
-  (file, line, fmt(MESSAGE.c_str(), optName.c_str()), cause),
+  (file, line, fmt(MESSAGE.c_str(), optName.c_str()), error_code::OPTION_ERROR,
+   cause),
   optName_(optName) {}
 
 OptionHandlerException::~OptionHandlerException() throw() {}

+ 3 - 1
src/OptionParser.cc

@@ -49,6 +49,7 @@
 #include "array_fun.h"
 #include "OptionHandlerFactory.h"
 #include "DlAbortEx.h"
+#include "error_code.h"
 
 namespace aria2 {
 
@@ -158,7 +159,8 @@ void OptionParser::parseArg
       op = findByShortName(c);
     }
     if(!op) {
-      throw DL_ABORT_EX("Failed to parse command-line options.");
+      throw DL_ABORT_EX2("Failed to parse command-line options.",
+                         error_code::OPTION_ERROR);
     }
     out << op->getName() << "=";
     if(optarg) {

+ 7 - 0
src/RecoverableException.cc

@@ -47,6 +47,13 @@ RecoverableException::RecoverableException
   : Exception(file, line, msg)
 {}
 
+RecoverableException::RecoverableException
+(const char* file, int line, const std::string& msg,
+ error_code::Value errorCode,
+ const Exception& cause)
+  : Exception(file, line, msg, errorCode, cause)
+{}
+
 RecoverableException::RecoverableException
 (const char* file, int line, const std::string& msg,
  const Exception& cause)

+ 4 - 0
src/RecoverableException.h

@@ -44,6 +44,10 @@ protected:
 public:
   RecoverableException(const char* file, int line, const std::string& msg);
 
+  RecoverableException(const char* file, int line, const std::string& msg,
+                       error_code::Value errorCode,
+                       const Exception& cause);
+
   RecoverableException(const char* file, int line, const std::string& msg,
                        const Exception& cause);
 

+ 15 - 7
src/XML2SAXMetalinkProcessor.cc

@@ -44,6 +44,7 @@
 #include "message.h"
 #include "DlAbortEx.h"
 #include "A2STR.h"
+#include "error_code.h"
 
 namespace aria2 {
 
@@ -200,13 +201,16 @@ MetalinkProcessor::parseFile(const std::string& filename)
   int retval = xmlSAXUserParseFile(&mySAXHandler, sessionData.get(),
                                    nfilename.c_str());
   if(retval != 0) {
-    throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK);
+    throw DL_ABORT_EX2(MSG_CANNOT_PARSE_METALINK,
+                       error_code::METALINK_PARSE_ERROR);
   }
   if(!stm_->finished()) {
-    throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK);
+    throw DL_ABORT_EX2(MSG_CANNOT_PARSE_METALINK,
+                       error_code::METALINK_PARSE_ERROR);
   }
   if(!stm_->getErrors().empty()) {
-    throw DL_ABORT_EX(stm_->getErrorString());
+    throw DL_ABORT_EX2(stm_->getErrorString(),
+                       error_code::METALINK_PARSE_ERROR);
   }
   return stm_->getResult();
 }
@@ -220,7 +224,8 @@ MetalinkProcessor::parseFromBinaryStream(const SharedHandle<BinaryStream>& binar
 
   ssize_t res = binaryStream->readData(buf, 4, 0);
   if(res != 4) {
-    throw DL_ABORT_EX("Too small data for parsing XML.");
+    throw DL_ABORT_EX2("Too small data for parsing XML.",
+                       error_code::METALINK_PARSE_ERROR);
   }
 
   SharedHandle<SessionData> sessionData(new SessionData(stm_));
@@ -236,17 +241,20 @@ MetalinkProcessor::parseFromBinaryStream(const SharedHandle<BinaryStream>& binar
       break;
     }
     if(xmlParseChunk(ctx, reinterpret_cast<const char*>(buf), res, 0) != 0) {
-      throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK);
+      throw DL_ABORT_EX2(MSG_CANNOT_PARSE_METALINK,
+                         error_code::METALINK_PARSE_ERROR);
     }
     readOffset += res;
   }
   xmlParseChunk(ctx, reinterpret_cast<const char*>(buf), 0, 1);
 
   if(!stm_->finished()) {
-    throw DL_ABORT_EX(MSG_CANNOT_PARSE_METALINK);
+    throw DL_ABORT_EX2(MSG_CANNOT_PARSE_METALINK,
+                       error_code::METALINK_PARSE_ERROR);
   }
   if(!stm_->getErrors().empty()) {
-    throw DL_ABORT_EX(stm_->getErrorString());
+    throw DL_ABORT_EX2(stm_->getErrorString(),
+                       error_code::METALINK_PARSE_ERROR);
   }
   return stm_->getResult();
 }

+ 28 - 18
src/bencode2.cc

@@ -39,6 +39,7 @@
 
 #include "fmt.h"
 #include "DlAbortEx.h"
+#include "error_code.h"
 
 namespace aria2 {
 
@@ -53,9 +54,10 @@ void checkdelim(std::istream& ss, const char delim = ':')
 {
   char d;
   if(!(ss.get(d) && d == delim)) {
-    throw DL_ABORT_EX
+    throw DL_ABORT_EX2
       (fmt("Bencode decoding failed: Delimiter '%c' not found.",
-           delim));
+           delim),
+       error_code::BENCODE_PARSE_ERROR);
   }
 }
 } // namespace
@@ -66,8 +68,9 @@ std::string decoderawstring(std::istream& ss)
   int length;
   ss >> length;
   if(!ss || length < 0) {
-    throw DL_ABORT_EX("Bencode decoding failed:"
-                      " A positive integer expected but none found.");
+    throw DL_ABORT_EX2("Bencode decoding failed:"
+                       " A positive integer expected but none found.",
+                       error_code::BENCODE_PARSE_ERROR);
   }
   // TODO check length, it must be less than or equal to INT_MAX
   checkdelim(ss);
@@ -76,11 +79,12 @@ std::string decoderawstring(std::istream& ss)
   std::string str(&buf[0], &buf[length]);
   delete [] buf;
   if(ss.gcount() != static_cast<int>(length)) {
-    throw DL_ABORT_EX
+    throw DL_ABORT_EX2
       (fmt("Bencode decoding failed:"
            " Expected %lu bytes of data, but only %ld read.",
            static_cast<unsigned long>(length),
-           static_cast<long int>(ss.gcount())));
+           static_cast<long int>(ss.gcount())),
+       error_code::BENCODE_PARSE_ERROR);
   }
   return str;
 }
@@ -99,8 +103,9 @@ SharedHandle<ValueBase> decodeinteger(std::istream& ss)
   Integer::ValueType iv;
   ss >> iv;
   if(!ss) {
-    throw DL_ABORT_EX("Bencode decoding failed:"
-                      " Integer expected but none found");
+    throw DL_ABORT_EX2("Bencode decoding failed:"
+                       " Integer expected but none found",
+                       error_code::BENCODE_PARSE_ERROR);
   }
   checkdelim(ss, 'e');
   return Integer::g(iv);
@@ -121,8 +126,9 @@ SharedHandle<ValueBase> decodedict(std::istream& ss, size_t depth)
       dict->put(key, decodeiter(ss, depth));
     }
   }
-  throw DL_ABORT_EX("Bencode decoding failed:"
-                    " Unexpected EOF in dict context. 'e' expected.");
+  throw DL_ABORT_EX2("Bencode decoding failed:"
+                     " Unexpected EOF in dict context. 'e' expected.",
+                     error_code::BENCODE_PARSE_ERROR);
 }
 } // namespace
 
@@ -139,8 +145,9 @@ SharedHandle<ValueBase> decodelist(std::istream& ss, size_t depth)
       list->append(decodeiter(ss, depth));
     }
   }
-  throw DL_ABORT_EX("Bencode decoding failed:"
-                    " Unexpected EOF in list context. 'e' expected.");
+  throw DL_ABORT_EX2("Bencode decoding failed:"
+                     " Unexpected EOF in list context. 'e' expected.",
+                     error_code::BENCODE_PARSE_ERROR);
 }
 } // namespace
 
@@ -148,7 +155,8 @@ namespace {
 void checkDepth(size_t depth)
 {
   if(depth >= MAX_STRUCTURE_DEPTH) {
-    throw DL_ABORT_EX("Bencode decoding failed: Structure is too deep.");
+    throw DL_ABORT_EX2("Bencode decoding failed: Structure is too deep.",
+                       error_code::BENCODE_PARSE_ERROR);
   }
 }
 } // namespace
@@ -159,9 +167,10 @@ SharedHandle<ValueBase> decodeiter(std::istream& ss, size_t depth)
   checkDepth(depth);
   char c;
   if(!ss.get(c)) {
-    throw DL_ABORT_EX("Bencode decoding failed:"
-                      " Unexpected EOF in term context."
-                      " 'd', 'l', 'i' or digit is expected.");
+    throw DL_ABORT_EX2("Bencode decoding failed:"
+                       " Unexpected EOF in term context."
+                       " 'd', 'l', 'i' or digit is expected.",
+                       error_code::BENCODE_PARSE_ERROR);
   }
   if(c == 'd') {
     return decodedict(ss, depth+1);
@@ -215,9 +224,10 @@ SharedHandle<ValueBase> decodeFromFile(const std::string& filename)
   if(f) {
     return decode(f);
   } else {
-    throw DL_ABORT_EX
+    throw DL_ABORT_EX2
       (fmt("Bencode decoding failed: Cannot open file '%s'.",
-           filename.c_str()));
+           filename.c_str()),
+       error_code::BENCODE_PARSE_ERROR);
   }
 }
 

+ 31 - 16
src/bittorrent_helper.cc

@@ -58,6 +58,7 @@
 #include "Option.h"
 #include "prefs.h"
 #include "FileEntry.h"
+#include "error_code.h"
 
 namespace aria2 {
 
@@ -209,9 +210,10 @@ void extractFileEntries
     if(nameData) {
       utf8Name = util::encodeNonUtf8(nameData->s());
       if(util::detectDirTraversal(utf8Name)) {
-        throw DL_ABORT_EX
+        throw DL_ABORT_EX2
           (fmt(MSG_DIR_TRAVERSAL_DETECTED,
-               nameData->s().c_str()));
+               nameData->s().c_str()),
+           error_code::BITTORRENT_PARSE_ERROR);
       }
       name = nameData->s();
     } else {
@@ -237,7 +239,8 @@ void extractFileEntries
       }
       const Integer* fileLengthData = asInteger(fileDict->get(C_LENGTH));
       if(!fileLengthData) {
-        throw DL_ABORT_EX(fmt(MSG_MISSING_BT_INFO, C_LENGTH.c_str()));
+        throw DL_ABORT_EX2(fmt(MSG_MISSING_BT_INFO, C_LENGTH.c_str()),
+                           error_code::BITTORRENT_PARSE_ERROR);
       }
       length += fileLengthData->i();
 
@@ -249,7 +252,8 @@ void extractFileEntries
       }
       const List* pathList = asList(fileDict->get(pathKey));
       if(!pathList || pathList->empty()) {
-        throw DL_ABORT_EX("Path is empty.");
+        throw DL_ABORT_EX2("Path is empty.",
+                           error_code::BITTORRENT_PARSE_ERROR);
       }
       
       std::vector<std::string> pathelem(pathList->size()+1);
@@ -262,14 +266,16 @@ void extractFileEntries
         if(elem) {
           (*pathelemOutItr++) = elem->s();
         } else {
-          throw DL_ABORT_EX("Path element is not string.");
+          throw DL_ABORT_EX2("Path element is not string.",
+                             error_code::BITTORRENT_PARSE_ERROR);
         }
       }
       std::string path = strjoin(pathelem.begin(), pathelem.end(), '/');
       std::string utf8Path = strjoin(pathelem.begin(), pathelem.end(), '/',
                                      std::ptr_fun(util::encodeNonUtf8));
       if(util::detectDirTraversal(utf8Path)) {
-        throw DL_ABORT_EX(fmt(MSG_DIR_TRAVERSAL_DETECTED, utf8Path.c_str()));
+        throw DL_ABORT_EX2(fmt(MSG_DIR_TRAVERSAL_DETECTED, utf8Path.c_str()),
+                           error_code::BITTORRENT_PARSE_ERROR);
       }
       std::string pePath =
         strjoin(pathelem.begin(), pathelem.end(), '/',
@@ -289,7 +295,8 @@ void extractFileEntries
     torrent->mode = SINGLE;
     const Integer* lengthData = asInteger(infoDict->get(C_LENGTH));
     if(!lengthData) {
-      throw DL_ABORT_EX(fmt(MSG_MISSING_BT_INFO, C_LENGTH.c_str()));      
+      throw DL_ABORT_EX2(fmt(MSG_MISSING_BT_INFO, C_LENGTH.c_str()),
+                         error_code::BITTORRENT_PARSE_ERROR);
     }
     uint64_t totalLength = lengthData->i();
 
@@ -391,11 +398,13 @@ void processRootDictionary
 {
   const Dict* rootDict = asDict(root);
   if(!rootDict) {
-    throw DL_ABORT_EX("torrent file does not contain a root dictionary.");
+    throw DL_ABORT_EX2("torrent file does not contain a root dictionary.",
+                       error_code::BITTORRENT_PARSE_ERROR);
   }
   const Dict* infoDict = asDict(rootDict->get(C_INFO));
   if(!infoDict) {
-    throw DL_ABORT_EX(fmt(MSG_MISSING_BT_INFO, C_INFO.c_str()));
+    throw DL_ABORT_EX2(fmt(MSG_MISSING_BT_INFO, C_INFO.c_str()),
+                       error_code::BITTORRENT_PARSE_ERROR);
   }
   SharedHandle<TorrentAttribute> torrent(new TorrentAttribute());
 
@@ -413,7 +422,8 @@ void processRootDictionary
   // calculate the number of pieces
   const String* piecesData = asString(infoDict->get(C_PIECES));
   if(!piecesData) {
-    throw DL_ABORT_EX(fmt(MSG_MISSING_BT_INFO, C_PIECES.c_str()));
+    throw DL_ABORT_EX2(fmt(MSG_MISSING_BT_INFO, C_PIECES.c_str()),
+                       error_code::BITTORRENT_PARSE_ERROR);
   }
   // Commented out To download 0 length torrent.
   //   if(piecesData.s().empty()) {
@@ -427,7 +437,8 @@ void processRootDictionary
   // retrieve piece length
   const Integer* pieceLengthData = asInteger(infoDict->get(C_PIECE_LENGTH));
   if(!pieceLengthData) {
-    throw DL_ABORT_EX(fmt(MSG_MISSING_BT_INFO, C_PIECE_LENGTH.c_str()));
+    throw DL_ABORT_EX2(fmt(MSG_MISSING_BT_INFO, C_PIECE_LENGTH.c_str()),
+                       error_code::BITTORRENT_PARSE_ERROR);
   }
   size_t pieceLength = pieceLengthData->i();
   ctx->setPieceLength(pieceLength);
@@ -457,7 +468,8 @@ void processRootDictionary
   extractFileEntries
     (ctx, torrent, infoDict, defaultName, overrideName, urlList);
   if((ctx->getTotalLength()+pieceLength-1)/pieceLength != numPieces) {
-    throw DL_ABORT_EX("Too few/many piece hash.");
+    throw DL_ABORT_EX2("Too few/many piece hash.",
+                       error_code::BITTORRENT_PARSE_ERROR);
   }
   // retrieve announce
   extractAnnounce(torrent, rootDict);
@@ -908,11 +920,13 @@ SharedHandle<TorrentAttribute> parseMagnet(const std::string& magnet)
 {
   SharedHandle<Dict> r = magnet::parse(magnet);
   if(!r) {
-    throw DL_ABORT_EX("Bad BitTorrent Magnet URI.");
+    throw DL_ABORT_EX2("Bad BitTorrent Magnet URI.",
+                       error_code::MAGNET_PARSE_ERROR);
   }
   const List* xts = asList(r->get("xt"));
   if(!xts) {
-    throw DL_ABORT_EX("Missing xt parameter in Magnet URI.");
+    throw DL_ABORT_EX2("Missing xt parameter in Magnet URI.",
+                       error_code::MAGNET_PARSE_ERROR);
   }
   SharedHandle<TorrentAttribute> attrs(new TorrentAttribute());
   std::string infoHash;
@@ -936,8 +950,9 @@ SharedHandle<TorrentAttribute> parseMagnet(const std::string& magnet)
     }
   }
   if(infoHash.empty()) {
-    throw DL_ABORT_EX("Bad BitTorrent Magnet URI. "
-                      "No valid BitTorrent Info Hash found.");
+    throw DL_ABORT_EX2("Bad BitTorrent Magnet URI. "
+                       "No valid BitTorrent Info Hash found.",
+                       error_code::MAGNET_PARSE_ERROR);
   }
   const List* trs = asList(r->get("tr"));
   if(trs) {

+ 15 - 1
src/error_code.h

@@ -57,7 +57,21 @@ enum Value {
   DUPLICATE_DOWNLOAD = 11,
   DUPLICATE_INFO_HASH = 12,
   FILE_ALREADY_EXISTS = 13,
-  FILE_RENAMING_FAILED = 14
+  FILE_RENAMING_FAILED = 14,
+  FILE_OPEN_ERROR = 15,
+  FILE_CREATE_ERROR = 16,
+  FILE_IO_ERROR = 17,
+  DIR_CREATE_ERROR = 18,
+  NAME_RESOLVE_ERROR = 19,
+  METALINK_PARSE_ERROR = 20,
+  FTP_PROTOCOL_ERROR = 21,
+  HTTP_PROTOCOL_ERROR = 22,
+  HTTP_TOO_MANY_REDIRECTS = 23,
+  HTTP_AUTH_FAILED = 24,
+  BENCODE_PARSE_ERROR = 25,
+  BITTORRENT_PARSE_ERROR = 26,
+  MAGNET_PARSE_ERROR = 27,
+  OPTION_ERROR = 28
 };
 
 } // namespace error_code

+ 11 - 8
src/option_processing.cc

@@ -145,11 +145,11 @@ void option_processing(Option& op, std::vector<std::string>& uris,
                       << oparser.findByName(e.getOptionName())->getDescription()
                       << std::endl;
           }
-          exit(error_code::UNKNOWN_ERROR);
+          exit(e.getErrorCode());
         } catch(Exception& e) {
           std::cerr << "Parse error in " << cfname << "\n"
                     << e.stackTrace() << std::endl;
-          exit(error_code::UNKNOWN_ERROR);
+          exit(e.getErrorCode());
         }
       } else if(!ucfname.empty()) {
         std::cerr << fmt("Configuration file %s is not found.", cfname.c_str())
@@ -171,15 +171,18 @@ void option_processing(Option& op, std::vector<std::string>& uris,
     // finaly let's parse and store command-iine options.
     oparser.parse(op, cmdstream);
   } catch(OptionHandlerException& e) {
-    std::cerr << e.stackTrace() << "\n"
-              << "Usage:" << "\n"
-              << *oparser.findByName(e.getOptionName())
-              << std::endl;
-    exit(error_code::UNKNOWN_ERROR);
+    std::cerr << e.stackTrace() << "\n";
+    SharedHandle<OptionHandler> h = oparser.findByName(e.getOptionName());
+    if(h) {
+      std::cerr << "Usage:" << "\n"
+                << *h
+                << std::endl;
+    }
+    exit(e.getErrorCode());
   } catch(Exception& e) {
     std::cerr << e.stackTrace() << std::endl;
     showUsage(TAG_HELP, oparser);
-    exit(error_code::UNKNOWN_ERROR);
+    exit(e.getErrorCode());
   }
   if(
 #ifdef ENABLE_XML_RPC

+ 5 - 3
src/util.cc

@@ -1151,9 +1151,11 @@ void mkdirs(const std::string& dirpath)
   if(!dir.mkdirs()) {
     int errNum = errno;
     if(!dir.isDir()) {
-      throw DL_ABORT_EX
-        (fmt(EX_MAKE_DIR, dir.getPath().c_str(),
-             safeStrerror(errNum).c_str()));
+      throw DL_ABORT_EX3
+        (errNum,
+         fmt(EX_MAKE_DIR, dir.getPath().c_str(),
+             safeStrerror(errNum).c_str()),
+         error_code::DIR_CREATE_ERROR);
     }
   }
 }