Parcourir la source

2009-01-25 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	Added experimental built-in HTTP server. Currently, when a
	client accesses to the server, it responds with the current
	download progress. By default, it is disabled. To enable the
	server, give --enable-http-server option.  To change the default
	port number for the server to listen to, use
	--http-server-listen-port option.
	The response HTML is very simple and refreshes it self each 1
	second.  Because of this refresh, you see flicker in normal web
	browser such as Firefox.  I recommend to use console-based
	browser such as elinks, w3m.  To connect to the server, run
	'elinks http://localhost:6800/' while running aria2. Please
	replace port number '6800'(which is default) with your
	preference.	
	* src/DownloadEngineFactory.cc
	* src/HttpHeader.cc
	* src/HttpHeader.h
	* src/HttpHeaderProcessor.cc
	* src/HttpHeaderProcessor.h
	* src/HttpListenCommand.cc
	* src/HttpListenCommand.h
	* src/HttpServer.cc
	* src/HttpServer.h
	* src/HttpServerCommand.cc
	* src/HttpServerCommand.h
	* src/HttpServerResponseCommand.cc
	* src/HttpServerResponseCommand.h
	* src/Makefile.am
	* src/OptionHandlerFactory.cc
	* src/Util.cc
	* src/Util.h
	* src/help_tags.h
	* src/option_processing.cc
	* src/prefs.cc
	* src/prefs.h
	* src/usage_text.h
	* test/HttpHeaderProcessorTest.cc
	* test/UtilTest.cc
Tatsuhiro Tsujikawa il y a 16 ans
Parent
commit
0742e3921f

+ 38 - 0
ChangeLog

@@ -1,3 +1,41 @@
+2009-01-25  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	Added experimental built-in HTTP server. Currently, when a client
+	accesses to the server, it responds with the current download
+	progress. By default, it is disabled. To enable the server, give
+	--enable-http-server option.  To change the default port number
+	for the server to listen to, use --http-server-listen-port option.
+	The response HTML is very simple and refreshes it self each 1
+	second.  Because of this refresh, you see flicker in normal web
+	browser such as Firefox.  I recommend to use console-based browser
+	such as elinks, w3m.  To connect to the server, run 'elinks
+	http://localhost:6800/' while running aria2. Please replace port
+	number '6800'(which is default) with your preference.	
+	* src/DownloadEngineFactory.cc
+	* src/HttpHeader.cc
+	* src/HttpHeader.h
+	* src/HttpHeaderProcessor.cc
+	* src/HttpHeaderProcessor.h
+	* src/HttpListenCommand.cc
+	* src/HttpListenCommand.h
+	* src/HttpServer.cc
+	* src/HttpServer.h
+	* src/HttpServerCommand.cc
+	* src/HttpServerCommand.h
+	* src/HttpServerResponseCommand.cc
+	* src/HttpServerResponseCommand.h
+	* src/Makefile.am
+	* src/OptionHandlerFactory.cc
+	* src/Util.cc
+	* src/Util.h
+	* src/help_tags.h
+	* src/option_processing.cc
+	* src/prefs.cc
+	* src/prefs.h
+	* src/usage_text.h
+	* test/HttpHeaderProcessorTest.cc
+	* test/UtilTest.cc
+
 2009-01-24  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	Removed.

+ 10 - 0
src/DownloadEngineFactory.cc

@@ -63,6 +63,7 @@
 #include "SelectEventPoll.h"
 #include "DlAbortEx.h"
 #include "FileAllocationEntry.h"
+#include "HttpListenCommand.h"
 
 namespace aria2 {
 
@@ -138,6 +139,15 @@ DownloadEngineFactory::newDownloadEngine(Option* op,
 						stopSec));
     }
   }
+  if(op->getAsBool(PREF_ENABLE_HTTP_SERVER)) {
+    HttpListenCommand* httpListenCommand =
+      new HttpListenCommand(e->newCUID(), e.get());
+    if(httpListenCommand->bindPort(op->getAsInt(PREF_HTTP_SERVER_LISTEN_PORT))){
+      e->addRoutineCommand(httpListenCommand);
+    } else {
+      delete httpListenCommand;
+    }
+  }
   return e;
 }
 

+ 20 - 0
src/HttpHeader.cc

@@ -193,6 +193,26 @@ void HttpHeader::setVersion(const std::string& version)
   _version = version;
 }
 
+const std::string& HttpHeader::getMethod() const
+{
+  return _method;
+}
+
+void HttpHeader::setMethod(const std::string& method)
+{
+  _method = method;
+}
+
+const std::string& HttpHeader::getRequestPath() const
+{
+  return _requestPath;
+}
+
+void HttpHeader::setRequestPath(const std::string& requestPath)
+{
+  _requestPath = requestPath;
+}
+
 void HttpHeader::fill(std::istream& in)
 {
   std::string line;

+ 17 - 1
src/HttpHeader.h

@@ -36,12 +36,14 @@
 #define _D_HTTP_HEADER_H_
 
 #include "common.h"
-#include "SharedHandle.h"
+
 #include <map>
 #include <deque>
 #include <string>
 #include <iosfwd>
 
+#include "SharedHandle.h"
+
 namespace aria2 {
 
 class Range;
@@ -56,6 +58,12 @@ private:
 
   // HTTP version, e.g. HTTP/1.1
   std::string _version;
+
+  // HTTP Method, e.g. GET, POST, etc
+  std::string _method;
+
+  // Request Path
+  std::string _requestPath;
 public:
   HttpHeader() {}
   ~HttpHeader() {}
@@ -77,6 +85,14 @@ public:
 
   void setVersion(const std::string& version);
 
+  const std::string& getMethod() const;
+
+  void setMethod(const std::string& method);
+
+  const std::string& getRequestPath() const;
+
+  void setRequestPath(const std::string& requestPath);
+
   void fill(std::istream& in);
 
   // Clears table. _responseStatus and _version are unchanged.

+ 25 - 0
src/HttpHeaderProcessor.cc

@@ -111,6 +111,31 @@ SharedHandle<HttpHeader> HttpHeaderProcessor::getHttpResponseHeader()
   return httpHeader;
 }
 
+SharedHandle<HttpHeader> HttpHeaderProcessor::getHttpRequestHeader()
+{
+  // The minimum case of the first line is:
+  // GET / HTTP/1.x
+  // At least 14bytes before \r\n or \n.
+  std::string::size_type delimpos = std::string::npos;
+  if(((delimpos = _buf.find("\r\n")) == std::string::npos &&
+      (delimpos = _buf.find("\n")) == std::string::npos) ||
+     delimpos < 14) {
+    throw DlRetryEx(EX_NO_STATUS_HEADER);
+  }
+  std::deque<std::string> firstLine;
+  Util::slice(firstLine, _buf.substr(0, delimpos), ' ', true);
+  if(firstLine.size() != 3) {
+    throw DlAbortEx("Malformed HTTP request header.");    
+  }
+  SharedHandle<HttpHeader> httpHeader(new HttpHeader());
+  httpHeader->setMethod(firstLine[0]);
+  httpHeader->setRequestPath(firstLine[1]);
+  httpHeader->setVersion(firstLine[2]);
+  std::istringstream strm(_buf.substr(14));
+  httpHeader->fill(strm);
+  return httpHeader;
+}
+
 std::string HttpHeaderProcessor::getHeaderString() const
 {
   std::string::size_type delimpos = std::string::npos;

+ 3 - 1
src/HttpHeaderProcessor.h

@@ -74,7 +74,9 @@ public:
    * Processes the recieved header as a http response header and returns
    * HttpHeader object.
    */
-   SharedHandle<HttpHeader> getHttpResponseHeader();
+  SharedHandle<HttpHeader> getHttpResponseHeader();
+
+  SharedHandle<HttpHeader> getHttpRequestHeader();
 
   std::string getHeaderString() const;
 

+ 94 - 0
src/HttpListenCommand.cc

@@ -0,0 +1,94 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "HttpListenCommand.h"
+#include "DownloadEngine.h"
+#include "RecoverableException.h"
+#include "message.h"
+#include "Logger.h"
+#include "SocketCore.h"
+#include "HttpServerCommand.h"
+#include "CUIDCounter.h"
+#include "RequestGroupMan.h"
+
+namespace aria2 {
+
+HttpListenCommand::HttpListenCommand(int32_t cuid, DownloadEngine* e):
+  Command(cuid),_e(e) {}
+
+HttpListenCommand::~HttpListenCommand() {}
+
+bool HttpListenCommand::execute()
+{
+  if(_e->_requestGroupMan->downloadFinished() || _e->isHaltRequested()) {
+    return true;
+  }
+  try {
+    if(_serverSocket->isReadable(0)) {
+      SharedHandle<SocketCore> socket(_serverSocket->acceptConnection());
+      HttpServerCommand* c =
+	new HttpServerCommand(_e->newCUID(), _e, socket);
+      c->setStatus(Command::STATUS_ONESHOT_REALTIME);
+      _e->setNoWait(true);
+      _e->commands.push_back(c);
+    }
+  } catch(RecoverableException& e) {
+    logger->debug(MSG_ACCEPT_FAILURE, _e, cuid);
+  }
+  _e->commands.push_back(this);
+  return false;
+}
+
+bool HttpListenCommand::bindPort(uint16_t port)
+{
+  if(!_serverSocket.isNull()) {
+    _e->deleteSocketForReadCheck(_serverSocket, this);
+  }
+  _serverSocket.reset(new SocketCore());
+  logger->info("CUID#%d - Setting up HttpListenCommand", cuid);
+  try {
+    _serverSocket->bind(port);
+    _serverSocket->beginListen();
+    _serverSocket->setNonBlockingMode();
+    logger->info(MSG_LISTENING_PORT, cuid, port);
+    _e->addSocketForReadCheck(_serverSocket, this);
+    return true;
+  } catch(RecoverableException& e) {
+    logger->error(MSG_BIND_FAILURE, e, cuid, port);
+    _serverSocket->closeConnection();
+  }
+  return false;
+}
+
+} // namespace aria2

+ 62 - 0
src/HttpListenCommand.h

@@ -0,0 +1,62 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_HTTP_LISTEN_COMMAND_H_
+#define _D_HTTP_LISTEN_COMMAND_H_
+
+#include "Command.h"
+#include "SharedHandle.h"
+
+namespace aria2 {
+
+class DownloadEngine;
+class SocketCore;
+
+class HttpListenCommand : public Command {
+private:
+  DownloadEngine* _e;
+  SharedHandle<SocketCore> _serverSocket;
+public:
+  HttpListenCommand(int32_t cuid, DownloadEngine* e);
+
+  virtual ~HttpListenCommand();
+  
+  virtual bool execute();
+
+  bool bindPort(uint16_t port);
+};
+
+} // namespace aria2 
+
+#endif // _D_HTTP_LISTEN_COMMAND_H_

+ 96 - 0
src/HttpServer.cc

@@ -0,0 +1,96 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "HttpServer.h"
+#include "HttpHeader.h"
+#include "SocketCore.h"
+#include "HttpHeaderProcessor.h"
+#include "DlAbortEx.h"
+#include "message.h"
+#include "Util.h"
+
+namespace aria2 {
+
+HttpServer::HttpServer(const SharedHandle<SocketCore>& socket,
+		       DownloadEngine* e):
+  _socket(socket),
+  _socketBuffer(socket),
+  _e(e),
+  _headerProcessor(new HttpHeaderProcessor())
+{}
+
+HttpServer::~HttpServer() {}
+
+SharedHandle<HttpHeader> HttpServer::receiveRequest()
+{
+  size_t size = 512;
+  unsigned char buf[size];
+  _socket->peekData(buf, size);
+  if(size == 0 && !(_socket->wantRead() || _socket->wantWrite())) {
+    throw DlAbortEx(EX_EOF_FROM_PEER);
+  }
+  _headerProcessor->update(buf, size);
+  if(!_headerProcessor->eoh()) {
+    _socket->readData(buf, size);
+    return SharedHandle<HttpHeader>();
+  }
+  size_t putbackDataLength = _headerProcessor->getPutBackDataLength();
+  size -= putbackDataLength;
+  _socket->readData(buf, size);
+
+  return _headerProcessor->getHttpRequestHeader();
+}
+
+void HttpServer::feedResponse(const std::string& text)
+{
+  std::string header = "HTTP/1.0 200 OK\r\n"
+    "Content-Type: text/html\r\n"
+    "Content-Length: "+Util::uitos(text.size())+"\r\n"
+    "Connection: close\r\n"
+    "\r\n";
+  _socketBuffer.feedSendBuffer(header);
+  _socketBuffer.feedSendBuffer(text);
+}
+
+ssize_t HttpServer::sendResponse()
+{
+  return _socketBuffer.send();
+}
+
+bool HttpServer::sendBufferIsEmpty() const
+{
+  return _socketBuffer.sendBufferIsEmpty();
+}
+
+} // namespace aria2

+ 74 - 0
src/HttpServer.h

@@ -0,0 +1,74 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_HTTP_SERVER_H_
+#define _D_HTTP_SERVER_H_
+
+#include "common.h"
+
+#include <string>
+
+#include "SharedHandle.h"
+#include "SocketBuffer.h"
+
+namespace aria2 {
+
+class SocketCore;
+class HttpHeader;
+class HttpHeaderProcessor;
+class DownloadEngine;
+
+class HttpServer {
+private:
+  SharedHandle<SocketCore> _socket;
+  SocketBuffer _socketBuffer;
+  DownloadEngine* _e;
+  SharedHandle<HttpHeaderProcessor> _headerProcessor;
+public:
+  HttpServer(const SharedHandle<SocketCore>& socket, DownloadEngine* e);
+
+  ~HttpServer();
+
+  SharedHandle<HttpHeader> receiveRequest();
+
+  void feedResponse(const std::string& text);
+
+  ssize_t sendResponse();
+
+  bool sendBufferIsEmpty() const;
+};
+
+} // namespace aria2
+
+#endif // _D_HTTP_SERVER_H_

+ 247 - 0
src/HttpServerCommand.cc

@@ -0,0 +1,247 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "HttpServerCommand.h"
+
+#include <sstream>
+#include <algorithm>
+#include <iostream>
+#include <iomanip>
+
+#include "SocketCore.h"
+#include "DownloadEngine.h"
+#include "HttpServer.h"
+#include "HttpHeader.h"
+#include "Logger.h"
+#include "RequestGroup.h"
+#include "RequestGroupMan.h"
+#include "BtContext.h"
+#include "Util.h"
+#include "HttpServerResponseCommand.h"
+#include "CheckIntegrityEntry.h"
+#include "FileAllocationEntry.h"
+
+namespace aria2 {
+
+HttpServerCommand::HttpServerCommand(int32_t cuid, DownloadEngine* e,
+				     const SharedHandle<SocketCore>& socket):
+  Command(cuid),
+  _e(e),
+  _socket(socket),
+  _httpServer(new HttpServer(socket, e))
+{
+  _e->addSocketForReadCheck(_socket, this);
+}
+
+HttpServerCommand::~HttpServerCommand()
+{
+  _e->deleteSocketForReadCheck(_socket, this);
+}
+
+class PrintSummaryHtml
+{
+private:
+  std::ostream& _o;
+  
+public:
+  PrintSummaryHtml(std::ostream& o):_o(o) {}
+
+  void operator()(const SharedHandle<RequestGroup>& rg)
+  {
+    _o << "<div id=\"gid" << rg->getGID() << "\">"
+       << "[#" << rg->getGID() << "]"
+       << " FILE:" << "<strong>"
+       << Util::htmlEscape(rg->getFilePath()) << "</strong>";
+#ifdef ENABLE_BITTORRENT
+    SharedHandle<BtContext> btContext =
+      dynamic_pointer_cast<BtContext>(rg->getDownloadContext());
+    if(!btContext.isNull()) {
+      _o << "<br />" << "  Info Hash:" << btContext->getInfoHashAsString();
+    }
+#endif // ENABLE_BITTORRENT
+    _o << "<br />";
+
+    TransferStat stat = rg->calculateStat();
+    unsigned int eta = 0;
+    if(rg->getTotalLength() > 0 && stat.getDownloadSpeed() > 0) {
+      eta =
+	(rg->getTotalLength()-rg->getCompletedLength())/stat.getDownloadSpeed();
+    }
+#ifdef ENABLE_BITTORRENT
+    if(!btContext.isNull() && rg->downloadFinished()) {
+      _o << "SEEDING" << "(" << "ratio:"
+	 << std::fixed << std::setprecision(1)
+	 << ((stat.getAllTimeUploadLength()*10)/rg->getCompletedLength())/10.0
+	 << ") ";
+    }
+#endif // ENABLE_BITTORRENT
+    _o << Util::abbrevSize(rg->getCompletedLength())
+       << "B"
+       << "/"
+       << Util::abbrevSize(rg->getTotalLength())
+       << "B";
+    if(rg->getTotalLength() > 0) {
+      _o << "("
+	 << 100*rg->getCompletedLength()/rg->getTotalLength()
+	 << "%)";
+    }
+    _o << " "
+       << "CN:"
+       << rg->getNumConnection();
+    if(!rg->downloadFinished()) {
+      _o << " "
+	 << "SPD:"
+	 << std::fixed << std::setprecision(2)
+	 << stat.getDownloadSpeed()/1024.0 << "KiB/s";
+    }
+    if(stat.getSessionUploadLength() > 0) {
+      _o << " "
+	 << "UP:"
+	 << std::fixed << std::setprecision(2)
+	 << stat.getUploadSpeed()/1024.0 << "KiB/s"
+	 << "(" << Util::abbrevSize(stat.getAllTimeUploadLength()) << "B)";
+    }
+    if(eta > 0) {
+      _o << " "
+	<< "ETA:"
+	 << Util::htmlEscape(Util::secfmt(eta));
+    }
+    _o << "</div>"
+       << "<hr />";
+  }
+};
+
+static std::string createResponse(DownloadEngine* e)
+{
+  std::ostringstream strm;
+  const std::deque<SharedHandle<RequestGroup> > groups =
+    e->_requestGroupMan->getRequestGroups();
+  std::for_each(groups.begin(), groups.end(), PrintSummaryHtml(strm));
+
+  {
+    SharedHandle<FileAllocationEntry> entry =
+      e->_fileAllocationMan->getPickedEntry();
+    if(!entry.isNull()) {
+      strm << "<div id=\"filealloc\">"
+	   << "[FileAlloc:"
+	   << "#" << entry->getRequestGroup()->getGID() << " "
+	   << Util::abbrevSize(entry->getCurrentLength())
+	   << "B"
+	   << "/"
+	   << Util::abbrevSize(entry->getTotalLength())
+	   << "B"
+	   << "(";
+      if(entry->getTotalLength() > 0) {
+	strm << 100*entry->getCurrentLength()/entry->getTotalLength();
+      } else {
+	strm << "--";
+      }
+      strm << "%)"
+	<< "]";
+      if(e->_fileAllocationMan->hasNext()) {
+	strm << "("
+	     << e->_fileAllocationMan->countEntryInQueue()
+	     << "waiting...)";
+      }
+      strm << "</div><hr />";
+    }
+  }
+#ifdef ENABLE_MESSAGE_DIGEST
+  {
+    SharedHandle<CheckIntegrityEntry> entry =
+      e->_checkIntegrityMan->getPickedEntry();
+    if(!entry.isNull()) {
+      strm << "<div id=\"hashcheck\">"
+	   << "[HashCheck:"
+	   << "#" << entry->getRequestGroup()->getGID() << " "
+	   << Util::abbrevSize(entry->getCurrentLength())
+	   << "B"
+	   << "/"
+	   << Util::abbrevSize(entry->getTotalLength())
+	   << "B"
+	   << "("
+	   << 100*entry->getCurrentLength()/entry->getTotalLength()
+	   << "%)"
+	   << "]";
+      if(e->_checkIntegrityMan->hasNext()) {
+	strm << "("
+	     << e->_checkIntegrityMan->countEntryInQueue()
+	     << "waiting...)";
+      }
+      strm << "</div><hr />";
+    }
+  }
+#endif // ENABLE_MESSAGE_DIGEST
+  std::string body =
+    "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\""
+    " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"
+    "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">"
+    "<head>"
+    "<meta http-equiv=\"refresh\" content=\"1\" />"
+    "<title>aria2</title>"
+    "</head>"
+    "<body><h1>aria2 - Download Progress</h1>"+strm.str()+"</body>"
+    "</html>";
+  return body;
+}
+
+bool HttpServerCommand::execute()
+{
+  if(_socket->isReadable(0)) {
+    _timeout.reset();
+    SharedHandle<HttpHeader> header = _httpServer->receiveRequest();
+    if(header.isNull()) {
+      _e->commands.push_back(this);
+      return false;
+    } else {
+      _httpServer->feedResponse(createResponse(_e));
+      Command* command = new HttpServerResponseCommand(cuid, _httpServer, _e,
+						       _socket);
+      command->setStatus(Command::STATUS_ONESHOT_REALTIME);
+      _e->commands.push_back(command);
+      _e->setNoWait(true);
+      return true;
+    }
+  } else {
+    if(_timeout.elapsed(30)) {
+      logger->info("HTTP request timeout.");
+      return true;
+    } else {
+      _e->commands.push_back(this);
+      return false;
+    }
+  }
+}
+
+} // namespace aria2

+ 65 - 0
src/HttpServerCommand.h

@@ -0,0 +1,65 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_HTTP_SERVER_COMMAND_H_
+#define _D_HTTP_SERVER_COMMAND_H_
+
+#include "Command.h"
+#include "SharedHandle.h"
+#include "TimeA2.h"
+
+namespace aria2 {
+
+class DownloadEngine;
+class SocketCore;
+class HttpServer;
+
+class HttpServerCommand : public Command {
+private:
+  DownloadEngine* _e;
+  SharedHandle<SocketCore> _socket;
+  SharedHandle<HttpServer> _httpServer;
+  Time _timeout;
+public:
+  HttpServerCommand(int32_t cuid, DownloadEngine* e,
+		    const SharedHandle<SocketCore>& socket);
+
+  virtual ~HttpServerCommand();
+  
+  virtual bool execute();
+};
+
+} // namespace aria2 
+
+#endif // _D_HTTP_SERVER_COMMAND_H_

+ 80 - 0
src/HttpServerResponseCommand.cc

@@ -0,0 +1,80 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "HttpServerResponseCommand.h"
+#include "SocketCore.h"
+#include "DownloadEngine.h"
+#include "HttpServer.h"
+#include "Logger.h"
+
+namespace aria2 {
+
+HttpServerResponseCommand::HttpServerResponseCommand
+(int32_t cuid,
+ const SharedHandle<HttpServer>& httpServer,
+ DownloadEngine* e,
+ const SharedHandle<SocketCore>& socket):
+  Command(cuid),
+  _e(e),
+  _socket(socket),
+ _httpServer(httpServer)
+{
+ 
+  _e->addSocketForWriteCheck(_socket, this);
+}
+
+HttpServerResponseCommand::~HttpServerResponseCommand()
+{
+  _e->deleteSocketForWriteCheck(_socket, this);
+}
+
+bool HttpServerResponseCommand::execute()
+{
+  _httpServer->sendResponse();
+  if(_httpServer->sendBufferIsEmpty()) {
+    logger->info("CUID#%d - HttpServer: all response transmitted.", cuid);
+    return true;
+  } else {
+    if(_timeout.elapsed(10)) {
+      logger->info("CUID#%d - HttpServer: Timeout while trasmitting response.",
+		   cuid);
+      return true;
+    } else {
+      _e->commands.push_back(this);
+      return true;
+    }
+  }
+}
+
+} // namespace aria2

+ 67 - 0
src/HttpServerResponseCommand.h

@@ -0,0 +1,67 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2009 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_HTTP_SERVER_RESPONSE_COMMAND_H_
+#define _D_HTTP_SERVER_RESPONSE_COMMAND_H_
+
+#include "Command.h"
+#include "SharedHandle.h"
+#include "TimeA2.h"
+
+namespace aria2 {
+
+class DownloadEngine;
+class SocketCore;
+class HttpServer;
+
+class HttpServerResponseCommand : public Command {
+private:
+  DownloadEngine* _e;
+  SharedHandle<SocketCore> _socket;
+  SharedHandle<HttpServer> _httpServer;
+  Time _timeout;
+public:
+  HttpServerResponseCommand(int32_t cuid,
+			    const SharedHandle<HttpServer>& httpServer,
+			    DownloadEngine* e,
+			    const SharedHandle<SocketCore>& socket);
+
+  virtual ~HttpServerResponseCommand();
+  
+  virtual bool execute();
+};
+
+} // namespace aria2 
+
+#endif // _D_HTTP_SERVER_RESPONSE_COMMAND_H_

+ 5 - 1
src/Makefile.am

@@ -200,7 +200,11 @@ SRCS =  Socket.h\
 	EventPoll.h\
 	SelectEventPoll.cc SelectEventPoll.h\
 	SequentialPicker.h\
-	SequentialDispatcherCommand.h
+	SequentialDispatcherCommand.h\
+	HttpListenCommand.cc HttpListenCommand.h\
+	HttpServerCommand.cc HttpServerCommand.h\
+	HttpServerResponseCommand.cc HttpServerResponseCommand.h\
+	HttpServer.cc HttpServer.h
 
 if HAVE_EPOLL
 SRCS += EpollEventPoll.cc EpollEventPoll.h

+ 20 - 8
src/Makefile.in

@@ -414,6 +414,9 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
 	OptionHandlerException.h bencode.cc bencode.h URIResult.cc \
 	URIResult.h EventPoll.h SelectEventPoll.cc SelectEventPoll.h \
 	SequentialPicker.h SequentialDispatcherCommand.h \
+	HttpListenCommand.cc HttpListenCommand.h HttpServerCommand.cc \
+	HttpServerCommand.h HttpServerResponseCommand.cc \
+	HttpServerResponseCommand.h HttpServer.cc HttpServer.h \
 	EpollEventPoll.cc EpollEventPoll.h TLSContext.h \
 	LibgnutlsTLSContext.cc LibgnutlsTLSContext.h \
 	LibsslTLSContext.cc LibsslTLSContext.h GZipDecoder.cc \
@@ -810,14 +813,16 @@ am__objects_22 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \
 	NsCookieParser.$(OBJEXT) CookieStorage.$(OBJEXT) \
 	SocketBuffer.$(OBJEXT) OptionHandlerException.$(OBJEXT) \
 	bencode.$(OBJEXT) URIResult.$(OBJEXT) \
-	SelectEventPoll.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
-	$(am__objects_3) $(am__objects_4) $(am__objects_5) \
-	$(am__objects_6) $(am__objects_7) $(am__objects_8) \
-	$(am__objects_9) $(am__objects_10) $(am__objects_11) \
-	$(am__objects_12) $(am__objects_13) $(am__objects_14) \
-	$(am__objects_15) $(am__objects_16) $(am__objects_17) \
-	$(am__objects_18) $(am__objects_19) $(am__objects_20) \
-	$(am__objects_21)
+	SelectEventPoll.$(OBJEXT) HttpListenCommand.$(OBJEXT) \
+	HttpServerCommand.$(OBJEXT) \
+	HttpServerResponseCommand.$(OBJEXT) HttpServer.$(OBJEXT) \
+	$(am__objects_1) $(am__objects_2) $(am__objects_3) \
+	$(am__objects_4) $(am__objects_5) $(am__objects_6) \
+	$(am__objects_7) $(am__objects_8) $(am__objects_9) \
+	$(am__objects_10) $(am__objects_11) $(am__objects_12) \
+	$(am__objects_13) $(am__objects_14) $(am__objects_15) \
+	$(am__objects_16) $(am__objects_17) $(am__objects_18) \
+	$(am__objects_19) $(am__objects_20) $(am__objects_21)
 am_libaria2c_a_OBJECTS = $(am__objects_22)
 libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS)
 am__installdirs = "$(DESTDIR)$(bindir)"
@@ -1143,6 +1148,9 @@ SRCS = Socket.h SocketCore.cc SocketCore.h BinaryStream.h Command.cc \
 	OptionHandlerException.h bencode.cc bencode.h URIResult.cc \
 	URIResult.h EventPoll.h SelectEventPoll.cc SelectEventPoll.h \
 	SequentialPicker.h SequentialDispatcherCommand.h \
+	HttpListenCommand.cc HttpListenCommand.h HttpServerCommand.cc \
+	HttpServerCommand.h HttpServerResponseCommand.cc \
+	HttpServerResponseCommand.h HttpServer.cc HttpServer.h \
 	$(am__append_1) $(am__append_2) $(am__append_3) \
 	$(am__append_4) $(am__append_5) $(am__append_6) \
 	$(am__append_7) $(am__append_8) $(am__append_9) \
@@ -1406,12 +1414,16 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpHeader.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpHeaderProcessor.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpInitiateConnectionCommand.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpListenCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpProxyRequestCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpProxyResponseCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpRequest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpRequestCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpResponse.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpResponseCommand.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpServer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpServerCommand.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpServerResponseCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpSkipResponseCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/InOrderURISelector.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/InitialMetalinkParserState.Po@am__quote@

+ 19 - 1
src/OptionHandlerFactory.cc

@@ -150,6 +150,14 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     op->addTag(TAG_ADVANCED);
     handlers.push_back(op);
   }
+  {
+    SharedHandle<OptionHandler> op(new BooleanOptionHandler
+				   (PREF_ENABLE_HTTP_SERVER,
+				    TEXT_ENABLE_HTTP_SERVER,
+				    V_FALSE));
+    op->addTag(TAG_EXPERIMENTAL);
+    handlers.push_back(op);
+  }
   {
     std::string params[] = {
 #ifdef HAVE_EPOLL
@@ -187,6 +195,15 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     op->addTag(TAG_BASIC);
     handlers.push_back(op);
   }
+  {
+    SharedHandle<OptionHandler> op(new NumberOptionHandler
+				   (PREF_HTTP_SERVER_LISTEN_PORT,
+				    TEXT_HTTP_SERVER_LISTEN_PORT,
+				    "6800",
+				    1024, UINT16_MAX));
+    op->addTag(TAG_EXPERIMENTAL);
+    handlers.push_back(op);
+  }
   {
     SharedHandle<OptionHandler> op(new DefaultOptionHandler
 				   (PREF_INPUT_FILE,
@@ -1013,7 +1030,7 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
 				   ("help",
 				    TEXT_HELP,
 				    TAG_BASIC,
-				    StringFormat("%s,%s,%s,%s,%s,%s,%s,%s,all",
+				    StringFormat("%s,%s,%s,%s,%s,%s,%s,%s,%s,all",
 						 TAG_BASIC,
 						 TAG_ADVANCED,
 						 TAG_HTTP,
@@ -1021,6 +1038,7 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
 						 TAG_FTP,
 						 TAG_METALINK,
 						 TAG_BITTORRENT,
+						 TAG_EXPERIMENTAL,
 						 TAG_HELP).str()));
     op->addTag(TAG_BASIC);
     op->addTag(TAG_HELP);

+ 22 - 0
src/Util.cc

@@ -912,4 +912,26 @@ Util::getNumericNameInfo(const struct sockaddr* sockaddr, socklen_t len)
   return std::pair<std::string, uint16_t>(host, atoi(service)); // TODO
 }
 
+std::string Util::htmlEscape(const std::string& src)
+{
+  std::string dest;
+  for(std::string::const_iterator i = src.begin(); i != src.end(); ++i) {
+    char ch = *i;
+    if(ch == '<') {
+      dest += "&lt;";
+    } else if(ch == '>') {
+      dest += "&gt;";
+    } else if(ch == '&') {
+      dest += "&amp;";
+    } else if(ch == '\'') {
+      dest += "&#39;";
+    } else if(ch == '"') {
+      dest += "&quot;";
+    } else {
+      dest += ch;
+    }
+  }
+  return dest;
+}
+
 } // namespace aria2

+ 2 - 0
src/Util.h

@@ -277,6 +277,8 @@ public:
 
   static std::pair<std::string, uint16_t>
   getNumericNameInfo(const struct sockaddr* sockaddr, socklen_t len);
+
+  static std::string htmlEscape(const std::string& src);
 };
 
 } // namespace aria2

+ 1 - 0
src/help_tags.h

@@ -42,6 +42,7 @@
 #define TAG_FTP "ftp"
 #define TAG_METALINK "metalink"
 #define TAG_BITTORRENT "bittorrent"
+#define TAG_EXPERIMENTAL "experimental"
 #define TAG_HELP "help"
 
 #endif // _D_HELP_TAGS_H_

+ 9 - 0
src/option_processing.cc

@@ -192,6 +192,8 @@ Option* option_processing(int argc, char* const argv[])
       { PREF_NO_PROXY.c_str(), required_argument, &lopt, 235 },
       { PREF_USE_HEAD.c_str(), optional_argument, &lopt, 236 },
       { PREF_EVENT_POLL.c_str(), required_argument, &lopt, 237 },
+      { PREF_HTTP_SERVER_LISTEN_PORT.c_str(), required_argument, &lopt, 238 },
+      { PREF_ENABLE_HTTP_SERVER.c_str(), optional_argument, &lopt, 239 },
 #if defined ENABLE_BITTORRENT || defined ENABLE_METALINK
       { PREF_SHOW_FILES.c_str(), no_argument, NULL, 'S' },
       { PREF_SELECT_FILE.c_str(), required_argument, &lopt, 21 },
@@ -487,6 +489,13 @@ Option* option_processing(int argc, char* const argv[])
       case 237:
 	cmdstream << PREF_EVENT_POLL << "=" << optarg << "\n";
 	break;
+      case 238:
+	cmdstream << PREF_HTTP_SERVER_LISTEN_PORT << "=" << optarg << "\n";
+	break;
+      case 239:
+	cmdstream << PREF_ENABLE_HTTP_SERVER << "=" << toBoolArg(optarg)
+		  << "\n";
+	break;
       }
       break;
     }

+ 4 - 0
src/prefs.cc

@@ -150,6 +150,10 @@ const std::string PREF_MAX_FILE_NOT_FOUND("max-file-not-found");
 const std::string PREF_EVENT_POLL("event-poll");
 const std::string V_EPOLL("epoll");
 const std::string V_SELECT("select");
+// value: 1*digit
+const std::string PREF_HTTP_SERVER_LISTEN_PORT("http-server-listen-port");
+// value: true | false
+const std::string PREF_ENABLE_HTTP_SERVER("enable-http-server");
 
 /**
  * FTP related preferences

+ 4 - 0
src/prefs.h

@@ -154,6 +154,10 @@ extern const std::string PREF_MAX_FILE_NOT_FOUND;
 extern const std::string PREF_EVENT_POLL;
 extern const std::string V_EPOLL;
 extern const std::string V_SELECT;
+// value: 1*digit
+extern const std::string PREF_HTTP_SERVER_LISTEN_PORT;
+// value: true | false
+extern const std::string PREF_ENABLE_HTTP_SERVER;
 
 /**
  * FTP related preferences

+ 12 - 0
src/usage_text.h

@@ -462,3 +462,15 @@ _(" --use-head[=true|false]      Use HEAD method for the first request to the HT
   "                              server.")
 #define TEXT_EVENT_POLL \
 _(" --event-poll=POLL            Specify the method for polling events.")
+#define TEXT_HTTP_SERVER_LISTEN_PORT \
+_(" --http-server-listen-port=PORT Specify a port number for the built-in HTTP\n"\
+  "                              Server to listen to.")
+// Excluded from translation candidiates because it is subject to change.
+#define TEXT_ENABLE_HTTP_SERVER \
+  " --enable-http-server[=true|false] Enable the built-in HTTP server. Currently,\n"\
+  "                              this is the experimental feature and it just\n"\
+  "                              provides the current download progress. Use your\n"\
+  "                              web browser(recommend to use console-based one,\n"\
+  "                              such as elinks, w3m) to connect the server and see\n"\
+  "                              what's what."
+

+ 19 - 0
test/HttpHeaderProcessorTest.cc

@@ -20,6 +20,7 @@ class HttpHeaderProcessorTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testGetHttpResponseHeader_insufficientStatusLength);
   CPPUNIT_TEST(testBeyondLimit);
   CPPUNIT_TEST(testGetHeaderString);
+  CPPUNIT_TEST(testGetHttpRequestHeader);
   CPPUNIT_TEST_SUITE_END();
   
 public:
@@ -201,4 +202,22 @@ void HttpHeaderProcessorTest::testGetHeaderString()
 		       proc.getHeaderString());
 }
 
+void HttpHeaderProcessorTest::testGetHttpRequestHeader()
+{
+  HttpHeaderProcessor proc;
+  std::string request = "GET /index.html HTTP/1.1\r\n"
+    "Host: host\r\n"
+    "Connection: close\r\n"
+    "\r\n";
+
+  proc.update(request);
+
+  SharedHandle<HttpHeader> httpHeader = proc.getHttpRequestHeader();
+  CPPUNIT_ASSERT(!httpHeader.isNull());
+  CPPUNIT_ASSERT_EQUAL(std::string("GET"), httpHeader->getMethod());
+  CPPUNIT_ASSERT_EQUAL(std::string("/index.html"),httpHeader->getRequestPath());
+  CPPUNIT_ASSERT_EQUAL(std::string("HTTP/1.1"), httpHeader->getVersion());
+  CPPUNIT_ASSERT_EQUAL(std::string("close"),httpHeader->getFirst("Connection"));
+}
+
 } // namespace aria2

+ 8 - 0
test/UtilTest.cc

@@ -51,6 +51,7 @@ class UtilTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testHttpGMT);
   CPPUNIT_TEST(testNtoh64);
   CPPUNIT_TEST(testUrlencode);
+  CPPUNIT_TEST(testHtmlEscape);
   CPPUNIT_TEST_SUITE_END();
 private:
 
@@ -92,6 +93,7 @@ public:
   void testHttpGMT();
   void testNtoh64();
   void testUrlencode();
+  void testHtmlEscape();
 };
 
 
@@ -722,4 +724,10 @@ void UtilTest::testUrlencode()
   CPPUNIT_ASSERT_EQUAL(std::string("1%5EA%20"), Util::urlencode("1^A "));
 }
 
+void UtilTest::testHtmlEscape()
+{
+  CPPUNIT_ASSERT_EQUAL(std::string("aria2&lt;&gt;&quot;&#39;util"),
+		       Util::htmlEscape("aria2<>\"'util"));
+}
+
 } // namespace aria2