Prechádzať zdrojové kódy

2009-05-10 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	Added BASIC authentication for XML-RPC. Added --xml-rpc-user and
	--xml-rpc-passwd option.
	* src/HttpServer.cc
	* src/HttpServer.h
	* src/HttpServerCommand.cc
	* src/OptionHandlerFactory.cc
	* src/prefs.cc
	* src/prefs.h
	* src/usage_text.h
Tatsuhiro Tsujikawa 16 rokov pred
rodič
commit
7aefbb7338
8 zmenil súbory, kde vykonal 112 pridanie a 3 odobranie
  1. 12 0
      ChangeLog
  2. 36 1
      src/HttpServer.cc
  3. 18 0
      src/HttpServer.h
  4. 17 0
      src/HttpServerCommand.cc
  5. 14 0
      src/OptionHandlerFactory.cc
  6. 4 0
      src/prefs.cc
  7. 4 0
      src/prefs.h
  8. 7 2
      src/usage_text.h

+ 12 - 0
ChangeLog

@@ -1,3 +1,15 @@
+2009-05-10  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	Added BASIC authentication for XML-RPC. Added --xml-rpc-user and
+	--xml-rpc-passwd option.
+	* src/HttpServer.cc
+	* src/HttpServer.h
+	* src/HttpServerCommand.cc
+	* src/OptionHandlerFactory.cc
+	* src/prefs.cc
+	* src/prefs.h
+	* src/usage_text.h
+
 2009-05-10  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	Fixed the bug that SocketCore::isReadable() prevents aria2 from

+ 36 - 1
src/HttpServer.cc

@@ -44,6 +44,7 @@
 #include "Util.h"
 #include "LogFactory.h"
 #include "Logger.h"
+#include "Base64.h"
 
 namespace aria2 {
 
@@ -133,13 +134,28 @@ bool HttpServer::supportsPersistentConnection() const
 
 void HttpServer::feedResponse(const std::string& text, const std::string& contentType)
 {
-  std::string header = "HTTP/1.1 200 OK\r\n"
+  feedResponse("200 OK", "", text, contentType);
+}
+
+void HttpServer::feedResponse(const std::string& status,
+			      const std::string& headers,
+			      const std::string& text,
+			      const std::string& contentType)
+{
+  std::string header = "HTTP/1.1 "+status+"\r\n"
     "Content-Type: "+contentType+"\r\n"
     "Content-Length: "+Util::uitos(text.size())+"\r\n";
 
   if(!supportsPersistentConnection()) {
     header += "Connection: close\r\n";
   }
+  if(!headers.empty()) {
+    header += headers;
+    if(!Util::endsWith(headers, "\r\n")) {
+      header += "\r\n";
+    }
+  }
+
   header += "\r\n";
 
   _logger->debug("HTTP Server sends response:\n%s", header.c_str());
@@ -158,4 +174,23 @@ bool HttpServer::sendBufferIsEmpty() const
   return _socketBuffer.sendBufferIsEmpty();
 }
 
+bool HttpServer::authenticate()
+{
+  if(_username.empty()) {
+    return true;
+  }
+
+  std::string authHeader = _lastRequestHeader->getFirst("Authorization");
+  if(authHeader.empty()) {
+    return false;
+  }
+  std::pair<std::string, std::string> p = Util::split(authHeader, " ");
+  if(p.first != "Basic") {
+    return false;
+  }
+  std::string userpass = Base64::decode(p.second);
+  std::pair<std::string, std::string> userpassPair = Util::split(userpass, ":");
+  return _username == userpassPair.first && _password == userpassPair.second;
+}
+
 } // namespace aria2

+ 18 - 0
src/HttpServer.h

@@ -62,6 +62,8 @@ private:
   uint64_t _lastContentLength;
   std::stringstream _lastBody;
   bool _keepAlive;
+  std::string _username;
+  std::string _password;
 public:
   HttpServer(const SharedHandle<SocketCore>& socket, DownloadEngine* e);
 
@@ -77,6 +79,20 @@ public:
 
   void feedResponse(const std::string& text, const std::string& contentType);
 
+  void feedResponse(const std::string& status,
+		    const std::string& headers,
+		    const std::string& text,
+		    const std::string& contentType);
+
+  bool authenticate();
+
+  void setUsernamePassword
+  (const std::string& username, const std::string& password)
+  {
+    _username = username;
+    _password = password;
+  }
+
   ssize_t sendResponse();
 
   bool sendBufferIsEmpty() const;
@@ -86,6 +102,8 @@ public:
   void enableKeepAlive() { _keepAlive = true; }
 
   void disableKeepAlive() { _keepAlive = false; }
+
+  uint64_t getContentLength() const { return _lastContentLength; }
 };
 
 } // namespace aria2

+ 17 - 0
src/HttpServerCommand.cc

@@ -41,7 +41,10 @@
 #include "RequestGroup.h"
 #include "RequestGroupMan.h"
 #include "HttpServerBodyCommand.h"
+#include "HttpServerResponseCommand.h"
 #include "RecoverableException.h"
+#include "prefs.h"
+#include "Option.h"
 
 namespace aria2 {
 
@@ -53,6 +56,8 @@ HttpServerCommand::HttpServerCommand(int32_t cuid, DownloadEngine* e,
   _httpServer(new HttpServer(socket, e))
 {
   _e->addSocketForReadCheck(_socket, this);
+  _httpServer->setUsernamePassword(_e->option->get(PREF_XML_RPC_USER),
+				   _e->option->get(PREF_XML_RPC_PASSWD));
 }
 
 HttpServerCommand::HttpServerCommand(int32_t cuid,
@@ -87,6 +92,18 @@ bool HttpServerCommand::execute()
 		   e, cuid);
       return true;
     }
+    if(!_httpServer->authenticate()) {
+      _httpServer->disableKeepAlive();
+      _httpServer->feedResponse("401 Unauthorized",
+				"WWW-Authenticate: Basic realm=\"aria2\"",
+				"","text/html");
+      Command* command =
+	new HttpServerResponseCommand(cuid, _httpServer, _e, _socket);
+      command->setStatus(Command::STATUS_ONESHOT_REALTIME);
+      _e->commands.push_back(command);
+      _e->setNoWait(true);
+      return true;
+    }
     if(header.isNull()) {
       _e->commands.push_back(this);
       return false;

+ 14 - 0
src/OptionHandlerFactory.cc

@@ -364,6 +364,20 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     op->addTag(TAG_ADVANCED);
     handlers.push_back(op);
   }
+  {
+    SharedHandle<OptionHandler> op(new DefaultOptionHandler
+				   (PREF_XML_RPC_USER,
+				    TEXT_XML_RPC_USER));
+    op->addTag(TAG_ADVANCED);
+    handlers.push_back(op);
+  }
+  {
+    SharedHandle<OptionHandler> op(new DefaultOptionHandler
+				   (PREF_XML_RPC_PASSWD,
+				    TEXT_XML_RPC_PASSWD));
+    op->addTag(TAG_ADVANCED);
+    handlers.push_back(op);
+  }			    
 #endif // ENABLE_XML_RPC
   // HTTP/FTP options
   {

+ 4 - 0
src/prefs.cc

@@ -163,6 +163,10 @@ const std::string PREF_RESET_URI("reset-uri");
 const std::string PREF_DRY_RUN("dry-run");
 // value: true | false
 const std::string PREF_REUSE_URI("reuse-uri");
+// value: string
+const std::string PREF_XML_RPC_USER("xml-rpc-user");
+// value: string
+const std::string PREF_XML_RPC_PASSWD("xml-rpc-passwd");
 
 /**
  * FTP related preferences

+ 4 - 0
src/prefs.h

@@ -167,6 +167,10 @@ extern const std::string PREF_RESET_URI;
 extern const std::string PREF_DRY_RUN;
 // value: true | false
 extern const std::string PREF_REUSE_URI;
+// value: string
+extern const std::string PREF_XML_RPC_USER;
+// value: string
+extern const std::string PREF_XML_RPC_PASSWD;
 
 /**
  * FTP related preferences

+ 7 - 2
src/usage_text.h

@@ -481,10 +481,15 @@ _(" --event-poll=POLL            Specify the method for polling events.")
 #define TEXT_XML_RPC_LISTEN_PORT \
 _(" --xml-rpc-listen-port=PORT   Specify a port number for XML-RPC server to listen\n"\
   "                              to.")
-// Excluded from translation candidiates because it is subject to change.
 #define TEXT_ENABLE_XML_RPC \
 _(" --enable-xml-rpc[=true|false] Enable XML-RPC server.\n"\
-  "                              See also --xml-rpc-listen-port option.")
+  "                              It is strongly recommended to set username and\n"\
+  "                              password using --xml-rpc-user and --xml-rpc-passwd\n"\
+  "                              option. See also --xml-rpc-listen-port option.")
+#define TEXT_XML_RPC_USER \
+_(" --xml-rpc-user=USER          Set XML-RPC user.")
+#define TEXT_XML_RPC_PASSWD \
+_(" --xml-rpc-passwd=PASSWD      Set XML-RPC password.")
 #define TEXT_BT_EXTERNAL_IP \
 _(" --bt-external-ip=IPADDRESS   Specify the external IP address to report to a\n"\
   "                              BitTorrent tracker. Although this function is\n"\