Browse Source

2008-05-07 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

	Receive content body of 302 response so that the connection can 
be
	reused later when http keep-alive is enabled.
	* src/HttpNullDownloadCommand.cc
	* src/HttpNullDownloadCommand.h
	* src/HttpResponseCommand.cc
	* src/HttpResponseCommand.h
Tatsuhiro Tsujikawa 17 years ago
parent
commit
4f150057ca
5 changed files with 238 additions and 5 deletions
  1. 9 0
      ChangeLog
  2. 115 0
      src/HttpNullDownloadCommand.cc
  3. 75 0
      src/HttpNullDownloadCommand.h
  4. 37 5
      src/HttpResponseCommand.cc
  5. 2 0
      src/HttpResponseCommand.h

+ 9 - 0
ChangeLog

@@ -1,3 +1,12 @@
+2008-05-07  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	Receive content body of 302 response so that the connection can be
+	reused later when http keep-alive is enabled.
+	* src/HttpNullDownloadCommand.cc
+	* src/HttpNullDownloadCommand.h
+	* src/HttpResponseCommand.cc
+	* src/HttpResponseCommand.h
+
 2008-05-07  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
 
 	const SharedHandle<Request> -> const SharedHandle<Request>&

+ 115 - 0
src/HttpNullDownloadCommand.cc

@@ -0,0 +1,115 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 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 "HttpNullDownloadCommand.h"
+#include "HttpConnection.h"
+#include "HttpResponse.h"
+#include "message.h"
+#include "SocketCore.h"
+#include "TransferEncoding.h"
+#include "DlRetryEx.h"
+#include "Request.h"
+#include "DownloadEngine.h"
+#include "Logger.h"
+#include "HttpRequest.h"
+#include "Segment.h"
+
+namespace aria2 {
+
+HttpNullDownloadCommand::HttpNullDownloadCommand
+(int cuid,
+ const SharedHandle<Request>& req,
+ RequestGroup* requestGroup,
+ const SharedHandle<HttpConnection>& httpConnection,
+ const SharedHandle<HttpResponse>& httpResponse,
+ DownloadEngine* e,
+ const SharedHandle<SocketCore>& s):
+  AbstractCommand(cuid, req, requestGroup, e, s),
+  _httpConnection(httpConnection),
+  _httpResponse(httpResponse),
+  _totalLength(_httpResponse->getEntityLength()),
+  _receivedBytes(0)
+{}
+
+HttpNullDownloadCommand::~HttpNullDownloadCommand() {}
+
+void HttpNullDownloadCommand::setTransferDecoder
+(const SharedHandle<TransferEncoding>& transferDecoder)
+{
+  _transferDecoder = transferDecoder;
+}
+
+bool HttpNullDownloadCommand::executeInternal()
+{
+  const size_t BUFSIZE = 16*1024;
+  unsigned char buf[BUFSIZE];
+  size_t bufSize = BUFSIZE;
+  socket->readData(buf, bufSize);
+
+  if(_transferDecoder.isNull()) {
+    _receivedBytes += bufSize;
+  } else {
+    // _receivedBytes is not updated if transferEncoding is set.
+    size_t infbufSize = 16*1024;
+    unsigned char infbuf[infbufSize];
+    _transferDecoder->inflate(infbuf, infbufSize, buf, bufSize);
+  }
+  if(_totalLength != 0 && bufSize == 0) {
+    throw DlRetryEx(EX_GOT_EOF);
+  }
+
+  if(bufSize == 0) {
+    // Since this method is called by DownloadEngine only when the socket is
+    // readable, bufSize == 0 means server shutdown the connection.
+    // So socket cannot be reused in this case.
+    return prepareForRetry(0);
+  } else if((!_transferDecoder.isNull() && _transferDecoder->finished())
+	    || (_transferDecoder.isNull() && _totalLength == _receivedBytes)) {
+    if(!_transferDecoder.isNull()) _transferDecoder->end();
+
+    if(req->supportsPersistentConnection()) {
+      std::pair<std::string, uint16_t> peerInfo;
+      socket->getPeerInfo(peerInfo);
+      e->poolSocket(peerInfo.first, peerInfo.second, socket);
+    }
+    _httpResponse->processRedirect();
+    logger->info(MSG_REDIRECT, cuid, _httpResponse->getRedirectURI().c_str());
+    return prepareForRetry(0);
+  } else {
+    e->commands.push_back(this);
+    return false;
+  }
+}
+
+} // namespace aria2

+ 75 - 0
src/HttpNullDownloadCommand.h

@@ -0,0 +1,75 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 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_NULL_DOWNLOAD_COMMAND_H_
+#define _D_HTTP_NULL_DOWNLOAD_COMMAND_H_
+
+#include "AbstractCommand.h"
+
+namespace aria2 {
+
+class HttpConnection;
+class HttpResponse;
+class TransferEncoding;
+
+class HttpNullDownloadCommand : public AbstractCommand {
+private:
+  SharedHandle<HttpConnection> _httpConnection;
+
+  SharedHandle<HttpResponse> _httpResponse;
+
+  SharedHandle<TransferEncoding> _transferDecoder;
+
+  uint64_t _totalLength;
+
+  uint64_t _receivedBytes;
+protected:
+  virtual bool executeInternal();
+public:
+  HttpNullDownloadCommand(int cuid,
+			  const SharedHandle<Request>& req,
+			  RequestGroup* requestGroup,
+			  const SharedHandle<HttpConnection>& httpConnection,
+			  const SharedHandle<HttpResponse>& httpResponse,
+			  DownloadEngine* e,
+			  const SharedHandle<SocketCore>& s);
+
+  virtual ~HttpNullDownloadCommand();
+
+  void setTransferDecoder(const SharedHandle<TransferEncoding>& transferDecoder);
+};
+
+} // namespace aria2
+
+#endif // _D_HTTP_NULL_DOWNLOAD_COMMAND_H_

+ 37 - 5
src/HttpResponseCommand.cc

@@ -60,6 +60,7 @@
 #include "message.h"
 #include "prefs.h"
 #include "StringFormat.h"
+#include "HttpNullDownloadCommand.h"
 
 namespace aria2 {
 
@@ -88,11 +89,24 @@ bool HttpResponseCommand::executeInternal()
   httpResponse->retrieveCookie();
   // check whether Location header exists. If it does, update request object
   // with redirected URL.
-  // then establish a connection to the new host and port
   if(httpResponse->isRedirect()) {
-    httpResponse->processRedirect();
-    logger->info(MSG_REDIRECT, cuid, httpResponse->getRedirectURI().c_str());
-    return prepareForRetry(0);
+    // To reuse a connection, a response body must be received.
+    if(req->supportsPersistentConnection() &&
+       (httpResponse->getEntityLength() > 0 ||
+	httpResponse->isTransferEncodingSpecified())) {
+      return handleRedirect(httpResponse);
+    } else {
+      // Response body is 0 length or a response header shows that a persistent
+      // connection is not enabled.
+      if(req->supportsPersistentConnection()) {
+	std::pair<std::string, uint16_t> peerInfo;
+	socket->getPeerInfo(peerInfo);
+	e->poolSocket(peerInfo.first, peerInfo.second, socket);
+      }
+      httpResponse->processRedirect();
+      logger->info(MSG_REDIRECT, cuid, httpResponse->getRedirectURI().c_str());
+      return prepareForRetry(0);
+    }
   }
   if(!_requestGroup->isSingleHostMultiConnectionEnabled()) {
     _requestGroup->removeURIWhoseHostnameIs(_requestGroup->searchServerHost(cuid)->getHostname());
@@ -179,7 +193,8 @@ bool HttpResponseCommand::handleOtherEncoding(const HttpResponseHandle& httpResp
   return true;
 }
 
-HttpDownloadCommand* HttpResponseCommand::createHttpDownloadCommand(const HttpResponseHandle& httpResponse)
+static SharedHandle<TransferEncoding> getTransferEncoding
+(const SharedHandle<HttpResponse>& httpResponse)
 {
   TransferEncodingHandle enc;
   if(httpResponse->isTransferEncodingSpecified()) {
@@ -191,6 +206,23 @@ HttpDownloadCommand* HttpResponseCommand::createHttpDownloadCommand(const HttpRe
     }
     enc->init();
   }
+  return enc;
+}
+
+bool HttpResponseCommand::handleRedirect
+(const SharedHandle<HttpResponse>& httpResponse)
+{
+  SharedHandle<TransferEncoding> enc(getTransferEncoding(httpResponse));
+  HttpNullDownloadCommand* command = new HttpNullDownloadCommand
+    (cuid, req, _requestGroup, httpConnection, httpResponse, e, socket);
+  command->setTransferDecoder(enc);
+  e->commands.push_back(command);
+  return true;
+}
+
+HttpDownloadCommand* HttpResponseCommand::createHttpDownloadCommand(const HttpResponseHandle& httpResponse)
+{
+  TransferEncodingHandle enc(getTransferEncoding(httpResponse));
   HttpDownloadCommand* command =
     new HttpDownloadCommand(cuid, req, _requestGroup, httpConnection, e, socket);
   command->setMaxDownloadSpeedLimit(e->option->getAsInt(PREF_MAX_DOWNLOAD_LIMIT));

+ 2 - 0
src/HttpResponseCommand.h

@@ -50,6 +50,8 @@ private:
 
   bool handleDefaultEncoding(const SharedHandle<HttpResponse>& httpResponse);
   bool handleOtherEncoding(const SharedHandle<HttpResponse>& httpResponse);
+  bool handleRedirect(const SharedHandle<HttpResponse>& httpResponse);
+
   HttpDownloadCommand* createHttpDownloadCommand(const SharedHandle<HttpResponse>& httpResponse);
 protected:
   bool executeInternal();