/* */ #include "HttpResponseCommand.h" #include "DownloadEngine.h" #include "HttpResponse.h" #include "HttpConnection.h" #include "SegmentMan.h" #include "DlAbortEx.h" #include "DlRetryEx.h" #include "HttpDownloadCommand.h" #include "message.h" #include "Util.h" #include "prefs.h" #include "File.h" #include "InitiateConnectionCommandFactory.h" #include "SingleFileDownloadContext.h" #include "DiskAdaptor.h" #include "PieceStorage.h" #include "DefaultBtProgressInfoFile.h" #include #include HttpResponseCommand::HttpResponseCommand(int32_t cuid, const RequestHandle& req, RequestGroup* requestGroup, const HttpConnectionHandle& httpConnection, DownloadEngine* e, const SocketHandle& s) :AbstractCommand(cuid, req, requestGroup, e, s), httpConnection(httpConnection) {} HttpResponseCommand::~HttpResponseCommand() {} bool HttpResponseCommand::executeInternal() { HttpRequestHandle httpRequest = httpConnection->getFirstHttpRequest(); HttpResponseHandle httpResponse = httpConnection->receiveResponse(); if(httpResponse.isNull()) { // The server has not responded to our request yet. e->commands.push_back(this); return false; } // check HTTP status number httpResponse->validateResponse(); 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()); e->noWait = true; return prepareForRetry(0); } if(!_requestGroup->getPieceStorage().isNull()) { // validate totalsize _requestGroup->validateTotalLength(httpResponse->getEntityLength()); e->commands.push_back(createHttpDownloadCommand(httpResponse)); return true; } else { // validate totalsize against hintTotalSize if it is provided. _requestGroup->validateTotalLengthByHint(httpResponse->getEntityLength()); SingleFileDownloadContextHandle(_requestGroup->getDownloadContext())->setFilename(httpResponse->determinFilename()); if(httpResponse->isTransferEncodingSpecified()) { return handleOtherEncoding(httpResponse); } else { return handleDefaultEncoding(httpResponse); } } } bool HttpResponseCommand::handleDefaultEncoding(const HttpResponseHandle& httpResponse) { HttpRequestHandle httpRequest = httpResponse->getHttpRequest(); int64_t size = httpResponse->getEntityLength(); if(size == INT64_MAX || size < 0) { throw new DlAbortEx(EX_TOO_LARGE_FILE, Util::llitos(size, true).c_str()); } SingleFileDownloadContextHandle(_requestGroup->getDownloadContext())->setTotalLength(size); initPieceStorage(); // quick hack for method 'head',, is it necessary? if(httpRequest->getMethod() == Request::METHOD_HEAD) { // TODO because we don't want segment file to be saved. return true; } BtProgressInfoFileHandle infoFile = new DefaultBtProgressInfoFile(_requestGroup->getDownloadContext(), _requestGroup->getPieceStorage(), e->option); if(e->option->get(PREF_CHECK_INTEGRITY) != V_TRUE) { if(!infoFile->exists() && downloadFinishedByFileLength()) { logger->notice(MSG_DOWNLOAD_ALREADY_COMPLETED, cuid, _requestGroup->getFilePath().c_str()); return true; } } DownloadCommand* command = 0; try { loadAndOpenFile(infoFile); File file(_requestGroup->getFilePath()); if(_requestGroup->getRemainingUris().empty() && !file.exists()) { command = createHttpDownloadCommand(httpResponse); } prepareForNextAction(command); e->noWait = true; } catch(Exception* e) { delete command; throw; } return true; } bool HttpResponseCommand::handleOtherEncoding(const HttpResponseHandle& httpResponse) { // we ignore content-length when transfer-encoding is set HttpRequestHandle httpRequest = httpResponse->getHttpRequest(); // quick hack for method 'head',, is it necessary? if(httpRequest->getMethod() == Request::METHOD_HEAD) { return true; } // disable keep-alive req->setKeepAlive(false); initPieceStorage(); shouldCancelDownloadForSafety(); // TODO handle file-size unknown case _requestGroup->getPieceStorage()->getDiskAdaptor()->initAndOpenFile(); e->commands.push_back(createHttpDownloadCommand(httpResponse)); return true; } HttpDownloadCommand* HttpResponseCommand::createHttpDownloadCommand(const HttpResponseHandle& httpResponse) { TransferEncodingHandle enc = 0; if(httpResponse->isTransferEncodingSpecified()) { enc = httpResponse->getTransferDecoder(); if(enc.isNull()) { throw new DlAbortEx(EX_TRANSFER_ENCODING_NOT_SUPPORTED, httpResponse->getTransferEncoding().c_str()); } enc->init(); } HttpDownloadCommand* command = new HttpDownloadCommand(cuid, req, _requestGroup, httpConnection, e, socket); command->setMaxDownloadSpeedLimit(e->option->getAsInt(PREF_MAX_DOWNLOAD_LIMIT)); command->setStartupIdleTime(e->option->getAsInt(PREF_STARTUP_IDLE_TIME)); command->setLowestDownloadSpeedLimit(e->option->getAsInt(PREF_LOWEST_SPEED_LIMIT)); command->setTransferDecoder(enc); return command; }