/* */ #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 against hintTotalSize if it is provided. int64_t totalLength = httpResponse->getEntityLength(); _requestGroup->validateTotalLengthByHint(totalLength); SingleFileDownloadContextHandle dctx = _requestGroup->getDownloadContext(); dctx->setTotalLength(totalLength); dctx->setFilename(httpResponse->determinFilename()); if(totalLength == 0 || httpResponse->isTransferEncodingSpecified()) { // we ignore content-length when transfer-encoding is set dctx->setTotalLength(0); return handleOtherEncoding(httpResponse); } else { return handleDefaultEncoding(httpResponse); } } else { // validate totalsize _requestGroup->validateTotalLength(httpResponse->getEntityLength()); e->commands.push_back(createHttpDownloadCommand(httpResponse)); return true; } } bool HttpResponseCommand::handleDefaultEncoding(const HttpResponseHandle& httpResponse) { HttpRequestHandle httpRequest = httpResponse->getHttpRequest(); _requestGroup->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(!infoFile->exists() && _requestGroup->downloadFinishedByFileLength()) { return true; } DownloadCommand* command = 0; try { _requestGroup->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) { 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); _requestGroup->initPieceStorage(); _requestGroup->shouldCancelDownloadForSafety(); _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; }