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
pull/1/head
Tatsuhiro Tsujikawa 2009-01-25 09:58:40 +00:00
parent 9505df51ef
commit 0742e3921f
26 changed files with 1023 additions and 12 deletions

View File

@ -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.

View File

@ -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;
}

View File

@ -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;

View File

@ -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.

View File

@ -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;

View File

@ -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
src/HttpListenCommand.cc Normal file
View File

@ -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
src/HttpListenCommand.h Normal file
View File

@ -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
src/HttpServer.cc Normal file
View File

@ -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
src/HttpServer.h Normal file
View File

@ -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
src/HttpServerCommand.cc Normal file
View File

@ -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
src/HttpServerCommand.h Normal file
View File

@ -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_

View File

@ -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

View File

@ -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_

View File

@ -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

View File

@ -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@

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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_

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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."

View File

@ -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

View File

@ -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