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

Persist connection between the built-in HTTP server and a client
	if a client supports keep-alive. Fixed the bug that aria2 exits
	when the HTTP server receives EOF from a client.	
	* src/HttpServer.cc
	* src/HttpServer.h
	* src/HttpServerCommand.cc
	* src/HttpServerCommand.h
	* src/HttpServerResponseCommand.cc
pull/1/head
Tatsuhiro Tsujikawa 2009-01-25 10:55:27 +00:00
parent 0742e3921f
commit 5def96906f
6 changed files with 88 additions and 7 deletions

View File

@ -1,3 +1,14 @@
2009-01-25 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Persist connection between the built-in HTTP server and a client
if a client supports keep-alive. Fixed the bug that aria2 exits
when the HTTP server receives EOF from a client.
* src/HttpServer.cc
* src/HttpServer.h
* src/HttpServerCommand.cc
* src/HttpServerCommand.h
* src/HttpServerResponseCommand.cc
2009-01-25 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net> 2009-01-25 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Added experimental built-in HTTP server. Currently, when a client Added experimental built-in HTTP server. Currently, when a client

View File

@ -39,6 +39,8 @@
#include "DlAbortEx.h" #include "DlAbortEx.h"
#include "message.h" #include "message.h"
#include "Util.h" #include "Util.h"
#include "LogFactory.h"
#include "Logger.h"
namespace aria2 { namespace aria2 {
@ -47,7 +49,8 @@ HttpServer::HttpServer(const SharedHandle<SocketCore>& socket,
_socket(socket), _socket(socket),
_socketBuffer(socket), _socketBuffer(socket),
_e(e), _e(e),
_headerProcessor(new HttpHeaderProcessor()) _headerProcessor(new HttpHeaderProcessor()),
_logger(LogFactory::getInstance())
{} {}
HttpServer::~HttpServer() {} HttpServer::~HttpServer() {}
@ -69,16 +72,40 @@ SharedHandle<HttpHeader> HttpServer::receiveRequest()
size -= putbackDataLength; size -= putbackDataLength;
_socket->readData(buf, size); _socket->readData(buf, size);
return _headerProcessor->getHttpRequestHeader(); SharedHandle<HttpHeader> header = _headerProcessor->getHttpRequestHeader();
if(!header.isNull()) {
_logger->info("HTTP Server received request\n%s",
_headerProcessor->getHeaderString().c_str());
_lastRequestHeader = header;
_headerProcessor->clear();
}
return header;
}
bool HttpServer::supportsPersistentConnection() const
{
std::string connection =
Util::toLower(_lastRequestHeader->getFirst(HttpHeader::CONNECTION));
return connection.find(HttpHeader::CLOSE) == std::string::npos &&
(_lastRequestHeader->getVersion() == HttpHeader::HTTP_1_1 ||
connection.find("keep-alive") != std::string::npos);
} }
void HttpServer::feedResponse(const std::string& text) void HttpServer::feedResponse(const std::string& text)
{ {
std::string header = "HTTP/1.0 200 OK\r\n" std::string header = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n" "Content-Type: text/html\r\n"
"Content-Length: "+Util::uitos(text.size())+"\r\n" "Content-Length: "+Util::uitos(text.size())+"\r\n";
"Connection: close\r\n"
"\r\n"; if(!supportsPersistentConnection()) {
header += "Connection: close\r\n";
}
header += "\r\n";
_logger->debug("HTTP Server sends response:\n%s", header.c_str());
_socketBuffer.feedSendBuffer(header); _socketBuffer.feedSendBuffer(header);
_socketBuffer.feedSendBuffer(text); _socketBuffer.feedSendBuffer(text);
} }

View File

@ -48,6 +48,7 @@ class SocketCore;
class HttpHeader; class HttpHeader;
class HttpHeaderProcessor; class HttpHeaderProcessor;
class DownloadEngine; class DownloadEngine;
class Logger;
class HttpServer { class HttpServer {
private: private:
@ -55,6 +56,8 @@ private:
SocketBuffer _socketBuffer; SocketBuffer _socketBuffer;
DownloadEngine* _e; DownloadEngine* _e;
SharedHandle<HttpHeaderProcessor> _headerProcessor; SharedHandle<HttpHeaderProcessor> _headerProcessor;
Logger* _logger;
SharedHandle<HttpHeader> _lastRequestHeader;
public: public:
HttpServer(const SharedHandle<SocketCore>& socket, DownloadEngine* e); HttpServer(const SharedHandle<SocketCore>& socket, DownloadEngine* e);
@ -67,6 +70,8 @@ public:
ssize_t sendResponse(); ssize_t sendResponse();
bool sendBufferIsEmpty() const; bool sendBufferIsEmpty() const;
bool supportsPersistentConnection() const;
}; };
} // namespace aria2 } // namespace aria2

View File

@ -51,6 +51,7 @@
#include "HttpServerResponseCommand.h" #include "HttpServerResponseCommand.h"
#include "CheckIntegrityEntry.h" #include "CheckIntegrityEntry.h"
#include "FileAllocationEntry.h" #include "FileAllocationEntry.h"
#include "RecoverableException.h"
namespace aria2 { namespace aria2 {
@ -64,6 +65,18 @@ HttpServerCommand::HttpServerCommand(int32_t cuid, DownloadEngine* e,
_e->addSocketForReadCheck(_socket, this); _e->addSocketForReadCheck(_socket, this);
} }
HttpServerCommand::HttpServerCommand(int32_t cuid,
const SharedHandle<HttpServer>& httpServer,
DownloadEngine* e,
const SharedHandle<SocketCore>& socket):
Command(cuid),
_e(e),
_socket(socket),
_httpServer(httpServer)
{
_e->addSocketForReadCheck(_socket, this);
}
HttpServerCommand::~HttpServerCommand() HttpServerCommand::~HttpServerCommand()
{ {
_e->deleteSocketForReadCheck(_socket, this); _e->deleteSocketForReadCheck(_socket, this);
@ -218,9 +231,19 @@ static std::string createResponse(DownloadEngine* e)
bool HttpServerCommand::execute() bool HttpServerCommand::execute()
{ {
if(_e->_requestGroupMan->downloadFinished() || _e->isHaltRequested()) {
return true;
}
if(_socket->isReadable(0)) { if(_socket->isReadable(0)) {
_timeout.reset(); _timeout.reset();
SharedHandle<HttpHeader> header = _httpServer->receiveRequest(); SharedHandle<HttpHeader> header;
try {
header = _httpServer->receiveRequest();
} catch(RecoverableException& e) {
logger->info("CUID#%d - Error occurred while reading HTTP request",
e, cuid);
return true;
}
if(header.isNull()) { if(header.isNull()) {
_e->commands.push_back(this); _e->commands.push_back(this);
return false; return false;

View File

@ -55,6 +55,11 @@ public:
HttpServerCommand(int32_t cuid, DownloadEngine* e, HttpServerCommand(int32_t cuid, DownloadEngine* e,
const SharedHandle<SocketCore>& socket); const SharedHandle<SocketCore>& socket);
HttpServerCommand(int32_t cuid,
const SharedHandle<HttpServer>& httpServer,
DownloadEngine* e,
const SharedHandle<SocketCore>& socket);
virtual ~HttpServerCommand(); virtual ~HttpServerCommand();
virtual bool execute(); virtual bool execute();

View File

@ -37,6 +37,8 @@
#include "DownloadEngine.h" #include "DownloadEngine.h"
#include "HttpServer.h" #include "HttpServer.h"
#include "Logger.h" #include "Logger.h"
#include "HttpServerCommand.h"
#include "RequestGroupMan.h"
namespace aria2 { namespace aria2 {
@ -61,9 +63,17 @@ HttpServerResponseCommand::~HttpServerResponseCommand()
bool HttpServerResponseCommand::execute() bool HttpServerResponseCommand::execute()
{ {
if(_e->_requestGroupMan->downloadFinished() || _e->isHaltRequested()) {
return true;
}
_httpServer->sendResponse(); _httpServer->sendResponse();
if(_httpServer->sendBufferIsEmpty()) { if(_httpServer->sendBufferIsEmpty()) {
logger->info("CUID#%d - HttpServer: all response transmitted.", cuid); logger->info("CUID#%d - HttpServer: all response transmitted.", cuid);
if(_httpServer->supportsPersistentConnection()) {
logger->info("CUID#%d - Persist connection.", cuid);
_e->commands.push_back
(new HttpServerCommand(cuid, _httpServer, _e, _socket));
}
return true; return true;
} else { } else {
if(_timeout.elapsed(10)) { if(_timeout.elapsed(10)) {