Explorar o código

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
Tatsuhiro Tsujikawa %!s(int64=16) %!d(string=hai) anos
pai
achega
5def96906f
Modificáronse 6 ficheiros con 88 adicións e 7 borrados
  1. 11 0
      ChangeLog
  2. 33 6
      src/HttpServer.cc
  3. 5 0
      src/HttpServer.h
  4. 24 1
      src/HttpServerCommand.cc
  5. 5 0
      src/HttpServerCommand.h
  6. 10 0
      src/HttpServerResponseCommand.cc

+ 11 - 0
ChangeLog

@@ -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>
 
 	Added experimental built-in HTTP server. Currently, when a client

+ 33 - 6
src/HttpServer.cc

@@ -39,6 +39,8 @@
 #include "DlAbortEx.h"
 #include "message.h"
 #include "Util.h"
+#include "LogFactory.h"
+#include "Logger.h"
 
 namespace aria2 {
 
@@ -47,7 +49,8 @@ HttpServer::HttpServer(const SharedHandle<SocketCore>& socket,
   _socket(socket),
   _socketBuffer(socket),
   _e(e),
-  _headerProcessor(new HttpHeaderProcessor())
+  _headerProcessor(new HttpHeaderProcessor()),
+  _logger(LogFactory::getInstance())
 {}
 
 HttpServer::~HttpServer() {}
@@ -69,16 +72,40 @@ SharedHandle<HttpHeader> HttpServer::receiveRequest()
   size -= putbackDataLength;
   _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)
 {
-  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-Length: "+Util::uitos(text.size())+"\r\n"
-    "Connection: close\r\n"
-    "\r\n";
+    "Content-Length: "+Util::uitos(text.size())+"\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(text);
 }

+ 5 - 0
src/HttpServer.h

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

+ 24 - 1
src/HttpServerCommand.cc

@@ -51,6 +51,7 @@
 #include "HttpServerResponseCommand.h"
 #include "CheckIntegrityEntry.h"
 #include "FileAllocationEntry.h"
+#include "RecoverableException.h"
 
 namespace aria2 {
 
@@ -64,6 +65,18 @@ HttpServerCommand::HttpServerCommand(int32_t cuid, DownloadEngine* e,
   _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()
 {
   _e->deleteSocketForReadCheck(_socket, this);
@@ -218,9 +231,19 @@ static std::string createResponse(DownloadEngine* e)
 
 bool HttpServerCommand::execute()
 {
+  if(_e->_requestGroupMan->downloadFinished() || _e->isHaltRequested()) {
+    return true;
+  }
   if(_socket->isReadable(0)) {
     _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()) {
       _e->commands.push_back(this);
       return false;

+ 5 - 0
src/HttpServerCommand.h

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

+ 10 - 0
src/HttpServerResponseCommand.cc

@@ -37,6 +37,8 @@
 #include "DownloadEngine.h"
 #include "HttpServer.h"
 #include "Logger.h"
+#include "HttpServerCommand.h"
+#include "RequestGroupMan.h"
 
 namespace aria2 {
 
@@ -61,9 +63,17 @@ HttpServerResponseCommand::~HttpServerResponseCommand()
 
 bool HttpServerResponseCommand::execute()
 {
+  if(_e->_requestGroupMan->downloadFinished() || _e->isHaltRequested()) {
+    return true;
+  }
   _httpServer->sendResponse();
   if(_httpServer->sendBufferIsEmpty()) {
     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;
   } else {
     if(_timeout.elapsed(10)) {