From e0aa767f9428eb34a7ab7c1169c1ecc55262dade Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 21 Feb 2006 12:28:42 +0000 Subject: [PATCH] --- src/FtpConnection.cc | 207 ++++++++++++++++++ src/FtpConnection.h | 65 ++++++ src/FtpDownloadCommand.cc | 38 ++++ src/FtpDownloadCommand.h | 37 ++++ src/FtpInitiateConnectionCommand.cc | 84 +++++++ src/FtpInitiateConnectionCommand.h | 39 ++++ src/FtpNegotiationCommand.cc | 328 ++++++++++++++++++++++++++++ src/FtpNegotiationCommand.h | 87 ++++++++ src/FtpTunnelRequestCommand.cc | 41 ++++ src/FtpTunnelRequestCommand.h | 35 +++ src/FtpTunnelResponseCommand.cc | 49 +++++ src/FtpTunnelResponseCommand.h | 39 ++++ src/HttpHeader.cc | 66 ++++++ src/HttpHeader.h | 46 ++++ 14 files changed, 1161 insertions(+) create mode 100644 src/FtpConnection.cc create mode 100644 src/FtpConnection.h create mode 100644 src/FtpDownloadCommand.cc create mode 100644 src/FtpDownloadCommand.h create mode 100644 src/FtpInitiateConnectionCommand.cc create mode 100644 src/FtpInitiateConnectionCommand.h create mode 100644 src/FtpNegotiationCommand.cc create mode 100644 src/FtpNegotiationCommand.h create mode 100644 src/FtpTunnelRequestCommand.cc create mode 100644 src/FtpTunnelRequestCommand.h create mode 100644 src/FtpTunnelResponseCommand.cc create mode 100644 src/FtpTunnelResponseCommand.h create mode 100644 src/HttpHeader.cc create mode 100644 src/HttpHeader.h diff --git a/src/FtpConnection.cc b/src/FtpConnection.cc new file mode 100644 index 00000000..4c528ada --- /dev/null +++ b/src/FtpConnection.cc @@ -0,0 +1,207 @@ +/* */ +#include "FtpConnection.h" +#include "Util.h" +#include "DlAbortEx.h" +#include "message.h" + +FtpConnection::FtpConnection(int cuid, const Socket* socket, const Request* req, const Option* op, const Logger* logger):cuid(cuid), socket(socket), req(req), option(op), logger(logger) {} + +FtpConnection::~FtpConnection() {} + +void FtpConnection::sendUser() const { + string request = "USER "+option->get("ftp_user")+"\r\n"; + logger->info(MSG_SENDING_FTP_REQUEST, cuid, request.c_str()); + socket->writeData(request); +} + +void FtpConnection::sendPass() const { + string request = "PASS "+option->get("ftp_passwd")+"\r\n"; + logger->info(MSG_SENDING_FTP_REQUEST, cuid, "PASS ********"); + socket->writeData(request); +} + +void FtpConnection::sendType() const { + string request = "TYPE "+option->get("ftp_type")+"\r\n"; + logger->info(MSG_SENDING_FTP_REQUEST, cuid, request.c_str()); + socket->writeData(request); +} + +void FtpConnection::sendCwd() const { + string request = "CWD "+req->getDir()+"\r\n"; + logger->info(MSG_SENDING_FTP_REQUEST, cuid, request.c_str()); + socket->writeData(request); +} + +void FtpConnection::sendSize() const { + string request = "SIZE "+req->getFile()+"\r\n"; + logger->info(MSG_SENDING_FTP_REQUEST, cuid, request.c_str()); + socket->writeData(request); +} + +void FtpConnection::sendPasv() const { + string request = "PASV\r\n"; + logger->info(MSG_SENDING_FTP_REQUEST, cuid, request.c_str()); + socket->writeData(request); +} + +Socket* FtpConnection::sendPort() const { + Socket* serverSocket = new Socket(); + try { + serverSocket->beginListen(); + + pair addrinfo; + socket->getAddrInfo(addrinfo); + int ipaddr[4]; + sscanf(addrinfo.first.c_str(), "%d.%d.%d.%d", + &ipaddr[0], &ipaddr[1], &ipaddr[2], &ipaddr[3]); + serverSocket->getAddrInfo(addrinfo); + string request = "PORT "+ + Util::itos(ipaddr[0])+","+Util::itos(ipaddr[1])+","+ + Util::itos(ipaddr[2])+","+Util::itos(ipaddr[3])+","+ + Util::itos(addrinfo.second/256)+","+Util::itos(addrinfo.second%256)+"\r\n"; + logger->info(MSG_SENDING_FTP_REQUEST, cuid, request.c_str()); + socket->writeData(request); + } catch (Exception* ex) { + delete serverSocket; + throw; + } + return serverSocket; +} + +void FtpConnection::sendRest(const Segment& segment) const { + string request = "REST "+Util::llitos(segment.sp+segment.ds)+"\r\n"; + logger->info(MSG_SENDING_FTP_REQUEST, cuid, request.c_str()); + socket->writeData(request); +} + +void FtpConnection::sendRetr() const { + string request = "RETR "+req->getFile()+"\r\n"; + logger->info(MSG_SENDING_FTP_REQUEST, cuid, request.c_str()); + socket->writeData(request); +} + +int FtpConnection::getStatus(string response) const { + int status; + // TODO we must handle when the response is not like "%d %*s" + // In this case, we return 0 + if(sscanf(response.c_str(), "%d %*s", &status) == 1) { + return status; + } else { + return 0; + } +} + +bool FtpConnection::isEndOfResponse(int status, string response) const { + if(response.size() <= 4) { + return false; + } + // if forth character of buf is '-', then multi line response is expected. + if(response.at(3) == '-') { + // multi line response + string::size_type p; + p = response.find("\r\n"+Util::itos(status)+" "); + if(p == string::npos) { + return false; + } + } + if(Util::endsWith(response, "\r\n")) { + return true; + } else { + return false; + } +} + +bool FtpConnection::bulkReceiveResponse(pair& response) { + char buf[1024]; + while(socket->isReadable(0)) { + int size = sizeof(buf)-1; + socket->readData(buf, size); + buf[size] = '\0'; + strbuf += buf; + } + int status; + if(strbuf.size() >= 4) { + status = getStatus(strbuf); + if(status == 0) { + throw new DlAbortEx(EX_INVALID_RESPONSE); + } + } else { + return false; + } + if(isEndOfResponse(status, strbuf)) { + logger->info(MSG_RECEIVE_RESPONSE, cuid, strbuf.c_str()); + response.first = status; + response.second = strbuf; + strbuf.erase(); + return true; + } else { + // didn't receive response fully. + return false; + } +} + +int FtpConnection::receiveResponse() { + pair response; + if(bulkReceiveResponse(response)) { + return response.first; + } else { + return 0; + } +} + +int FtpConnection::receiveSizeResponse(long long int& size) { + pair response; + if(bulkReceiveResponse(response)) { + if(response.first == 213) { + sscanf(response.second.c_str(), "%*d %Ld", &size); + } + return response.first; + } else { + return 0; + } +} + +int FtpConnection::receivePasvResponse(pair& dest) { + pair response; + if(bulkReceiveResponse(response)) { + if(response.first == 227) { + // we assume the format of response is "227 Entering Passive Mode (h1,h2,h3,h4,p1,p2)." + int h1, h2, h3, h4, p1, p2; + string::size_type p = response.second.find("("); + if(p >= 4) { + sscanf(response.second.substr(response.second.find("(")).c_str(), + "(%d,%d,%d,%d,%d,%d).", + &h1, &h2, &h3, &h4, &p1, &p2); + // ip address + dest.first = Util::itos(h1)+"."+Util::itos(h2)+"."+Util::itos(h3)+"."+Util::itos(h4); + // port number + dest.second = 256*p1+p2; + } else { + throw new DlAbortEx(EX_INVALID_RESPONSE); + } + } + return response.first; + } else { + return 0; + } +} diff --git a/src/FtpConnection.h b/src/FtpConnection.h new file mode 100644 index 00000000..6dab8e68 --- /dev/null +++ b/src/FtpConnection.h @@ -0,0 +1,65 @@ +/* */ +#ifndef _D_FTP_CONNECTION_H_ +#define _D_FTP_CONNECTION_H_ + +#include "Socket.h" +#include "Option.h" +#include "Logger.h" +#include "Segment.h" +#include "Request.h" +#include + +using namespace std; + +class FtpConnection { +private: + int cuid; + const Socket* socket; + const Request* req; + const Option* option; + const Logger* logger; + + string strbuf; + + int getStatus(string response) const; + bool isEndOfResponse(int status, string response) const; + bool bulkReceiveResponse(pair& response); +public: + FtpConnection(int cuid, const Socket* socket, const Request* req, const Option* op, const Logger* logger); + ~FtpConnection(); + void sendUser() const; + void sendPass() const; + void sendType() const; + void sendCwd() const; + void sendSize() const; + void sendPasv() const; + Socket* sendPort() const; + void sendRest(const Segment& segment) const; + void sendRetr() const; + + int receiveResponse(); + int receiveSizeResponse(long long int& size); + int receivePasvResponse(pair& dest); +}; + +#endif // _D_FTP_CONNECTION_H_ diff --git a/src/FtpDownloadCommand.cc b/src/FtpDownloadCommand.cc new file mode 100644 index 00000000..3d29c84c --- /dev/null +++ b/src/FtpDownloadCommand.cc @@ -0,0 +1,38 @@ +/* */ +#include "FtpDownloadCommand.h" + +FtpDownloadCommand::FtpDownloadCommand(int cuid, Request* req, DownloadEngine* e, Socket* dataSocket, Socket* ctrlSocket): + DownloadCommand(cuid, req, e, dataSocket) +{ + this->ctrlSocket = new Socket(*ctrlSocket); +} + +FtpDownloadCommand::~FtpDownloadCommand() { + if(ctrlSocket != NULL) { + delete ctrlSocket; + } +} + +TransferEncoding* FtpDownloadCommand::getTransferEncoding(string name) { + return NULL; +} diff --git a/src/FtpDownloadCommand.h b/src/FtpDownloadCommand.h new file mode 100644 index 00000000..b2db68a8 --- /dev/null +++ b/src/FtpDownloadCommand.h @@ -0,0 +1,37 @@ +/* */ +#ifndef _D_FTP_DOWNLOAD_COMMAND_H_ +#define _D_FTP_DOWNLOAD_COMMAND_H_ + +#include "DownloadCommand.h" + +class FtpDownloadCommand : public DownloadCommand { +private: + Socket* ctrlSocket; +public: + FtpDownloadCommand(int cuid, Request* req, DownloadEngine* e, Socket* dataSocket, Socket* ctrlSocket); + ~FtpDownloadCommand(); + + TransferEncoding* getTransferEncoding(string name); +}; + +#endif // _D_FTP_DOWNLOAD_COMMAND_H_ diff --git a/src/FtpInitiateConnectionCommand.cc b/src/FtpInitiateConnectionCommand.cc new file mode 100644 index 00000000..26bec02c --- /dev/null +++ b/src/FtpInitiateConnectionCommand.cc @@ -0,0 +1,84 @@ +/* */ +#include "FtpInitiateConnectionCommand.h" +#include "FtpNegotiationCommand.h" +#include "HttpRequestCommand.h" +#include "FtpTunnelRequestCommand.h" +#include "DlAbortEx.h" +#include "message.h" + +FtpInitiateConnectionCommand::FtpInitiateConnectionCommand(int cuid, Request* req, DownloadEngine* e):AbstractCommand(cuid, req, e) {} + +FtpInitiateConnectionCommand::~FtpInitiateConnectionCommand() {} + +bool FtpInitiateConnectionCommand::executeInternal(Segment segment) { + if(!e->segmentMan->downloadStarted) { + e->segmentMan->filename = req->getFile(); + bool segFileExists = e->segmentMan->segmentFileExists(); + if(segFileExists) { + e->segmentMan->load(); + e->diskWriter->openExistingFile(e->segmentMan->getFilePath()); + e->segmentMan->downloadStarted = true; + } else { + e->diskWriter->initAndOpenFile(e->segmentMan->getFilePath()); + } + } + + socket = new Socket(); + Command* command; + if(useHttpProxy()) { + e->logger->info(MSG_CONNECTING_TO_SERVER, cuid, + e->option->get("http_proxy_host").c_str(), + e->option->getAsInt("http_proxy_port")); + socket->establishConnection(e->option->get("http_proxy_host"), + e->option->getAsInt("http_proxy_port")); + + if(useHttpProxyGet()) { + command = new HttpRequestCommand(cuid, req, e, socket); + } else if(useHttpProxyConnect()) { + command = new FtpTunnelRequestCommand(cuid, req, e, socket); + } else { + // TODO + throw new DlAbortEx("ERROR"); + } + } else { + e->logger->info(MSG_CONNECTING_TO_SERVER, cuid, req->getHost().c_str(), + req->getPort()); + socket->establishConnection(req->getHost(), req->getPort()); + command = new FtpNegotiationCommand(cuid, req, e, socket); + } + e->commands.push(command); + return true; +} + +bool FtpInitiateConnectionCommand::useHttpProxy() const { + return e->option->defined("http_proxy_enabled") && + e->option->get("http_proxy_enabled") == "true"; +} + +bool FtpInitiateConnectionCommand::useHttpProxyGet() const { + return useHttpProxy() && e->option->get("ftp_via_http_proxy") == "get"; +} + +bool FtpInitiateConnectionCommand::useHttpProxyConnect() const { + return useHttpProxy() && e->option->get("ftp_via_http_proxy") == "tunnel"; +} diff --git a/src/FtpInitiateConnectionCommand.h b/src/FtpInitiateConnectionCommand.h new file mode 100644 index 00000000..0f997bf8 --- /dev/null +++ b/src/FtpInitiateConnectionCommand.h @@ -0,0 +1,39 @@ +/* */ +#ifndef _D_FTP_INITIATE_CONNECTION_COMMAND_H_ +#define _D_FTP_INITIATE_CONNECTION_COMMAND_H_ + +#include "AbstractCommand.h" + +class FtpInitiateConnectionCommand : public AbstractCommand { +private: + bool useHttpProxy() const; + bool useHttpProxyGet() const; + bool useHttpProxyConnect() const; +protected: + bool executeInternal(Segment segment); +public: + FtpInitiateConnectionCommand(int cuid, Request* req, DownloadEngine* e); + ~FtpInitiateConnectionCommand(); +}; + +#endif // _D_FTP_INITIATE_CONNECTION_COMMAND_H_ diff --git a/src/FtpNegotiationCommand.cc b/src/FtpNegotiationCommand.cc new file mode 100644 index 00000000..ee6821ec --- /dev/null +++ b/src/FtpNegotiationCommand.cc @@ -0,0 +1,328 @@ +/* */ +#include "FtpNegotiationCommand.h" +#include "FtpDownloadCommand.h" +#include "DlAbortEx.h" +#include "message.h" + +FtpNegotiationCommand::FtpNegotiationCommand(int cuid, Request* req, DownloadEngine* e, Socket* s): + AbstractCommand(cuid, req, e, s), + dataSocket(NULL), serverSocket(NULL), sequence(SEQ_RECV_GREETING) +{ + ftp = new FtpConnection(cuid, socket, req, e->option, e->logger); + setReadCheckSocket(NULL); + setWriteCheckSocket(socket); +} + +FtpNegotiationCommand::~FtpNegotiationCommand() { + if(dataSocket != NULL) { + delete dataSocket; + } + if(serverSocket != NULL) { + delete serverSocket; + } + delete ftp; +} + +bool FtpNegotiationCommand::executeInternal(Segment segment) { + while(processSequence(segment)); + if(sequence == SEQ_RETRY) { + return prepareForRetry(0); + } else if(sequence == SEQ_NEGOTIATION_COMPLETED) { + FtpDownloadCommand* command = new FtpDownloadCommand(cuid, req, e, dataSocket, socket); + e->commands.push(command); + return true; + } else { + e->commands.push(this); + return false; + } +} + +bool FtpNegotiationCommand::recvGreeting() { + socket->setBlockingMode(); + int status = ftp->receiveResponse(); + if(status == 0) { + return false; + } + if(status != 220) { + throw new DlAbortEx(EX_CONNECTION_FAILED); + } + sequence = SEQ_SEND_USER; + + setReadCheckSocket(socket); + setWriteCheckSocket(NULL); + + return true; +} + +bool FtpNegotiationCommand::sendUser() { + ftp->sendUser(); + sequence = SEQ_RECV_USER; + return false; +} + +bool FtpNegotiationCommand::recvUser() { + int status = ftp->receiveResponse(); + switch(status) { + case 0: + return false; + case 230: + sequence = SEQ_SEND_TYPE; + break; + case 331: + sequence = SEQ_SEND_PASS; + break; + default: + throw new DlAbortEx(EX_BAD_STATUS, status); + } + return true; +} + +bool FtpNegotiationCommand::sendPass() { + ftp->sendPass(); + sequence = SEQ_RECV_PASS; + return false; +} + +bool FtpNegotiationCommand::recvPass() { + int status = ftp->receiveResponse(); + if(status == 0) { + return false; + } + if(status != 230) { + throw new DlAbortEx(EX_BAD_STATUS, status); + } + sequence = SEQ_SEND_TYPE; + return true; +} + +bool FtpNegotiationCommand::sendType() { + ftp->sendType(); + sequence = SEQ_RECV_TYPE; + return false; +} + +bool FtpNegotiationCommand::recvType() { + int status = ftp->receiveResponse(); + if(status == 0) { + return false; + } + if(status != 200) { + throw new DlAbortEx(EX_BAD_STATUS, status); + } + sequence = SEQ_SEND_CWD; + return true; +} + +bool FtpNegotiationCommand::sendCwd() { + ftp->sendCwd(); + sequence = SEQ_RECV_CWD; + return false; +} + +bool FtpNegotiationCommand::recvCwd() { + int status = ftp->receiveResponse(); + if(status == 0) { + return false; + } + if(status != 250) { + throw new DlAbortEx(EX_BAD_STATUS, status); + } + sequence = SEQ_SEND_SIZE; + return true; +} + +bool FtpNegotiationCommand::sendSize() { + ftp->sendSize(); + sequence = SEQ_RECV_SIZE; + return false; +} + +bool FtpNegotiationCommand::recvSize() { + long long int size = 0; + int status = ftp->receiveSizeResponse(size); + if(status == 0) { + return false; + } + if(status != 213) { + throw new DlAbortEx(EX_BAD_STATUS, status); + } + // TODO check the value of size + if(!e->segmentMan->downloadStarted) { + e->segmentMan->downloadStarted = true; + e->segmentMan->totalSize = size; + } else if(e->segmentMan->totalSize != size) { + throw new DlAbortEx(EX_SIZE_MISMATCH, e->segmentMan->totalSize, size); + } + if(e->option->get("ftp_pasv_enabled") == "true") { + sequence = SEQ_SEND_PASV; + } else { + sequence = SEQ_SEND_PORT; + } + return true; +} + +bool FtpNegotiationCommand::sendPort() { + serverSocket = ftp->sendPort(); + sequence = SEQ_RECV_PORT; + return false; +} + +bool FtpNegotiationCommand::recvPort() { + int status = ftp->receiveResponse(); + if(status == 0) { + return false; + } + if(status != 200) { + throw new DlAbortEx(EX_BAD_STATUS, status); + } + sequence = SEQ_SEND_REST; + return true; +} + +bool FtpNegotiationCommand::sendPasv() { + ftp->sendPasv(); + sequence = SEQ_RECV_PASV; + return false; +} + +bool FtpNegotiationCommand::recvPasv() { + pair dest; + int status = ftp->receivePasvResponse(dest); + if(status == 0) { + return false; + } + if(status != 227) { + throw new DlAbortEx(EX_BAD_STATUS, status); + } + // make a data connection to the server. + dataSocket = new Socket(); + + e->logger->info(MSG_CONNECTING_TO_SERVER, cuid, + dest.first.c_str(), + dest.second); + dataSocket->establishConnection(dest.first, dest.second); + + setReadCheckSocket(NULL); + setWriteCheckSocket(dataSocket); + + sequence = SEQ_SEND_REST_PASV; + return false; +} + +bool FtpNegotiationCommand::sendRestPasv(const Segment& segment) { + dataSocket->setBlockingMode(); + setReadCheckSocket(socket); + setWriteCheckSocket(NULL); + return sendRest(segment); +} + +bool FtpNegotiationCommand::sendRest(const Segment& segment) { + ftp->sendRest(segment); + sequence = SEQ_RECV_REST; + return false; +} + +bool FtpNegotiationCommand::recvRest() { + int status = ftp->receiveResponse(); + if(status == 0) { + return false; + } + // TODO if we recieve negative response, then we set e->segmentMan->splittable = false, and continue. + if(status != 350) { + throw new DlAbortEx(EX_BAD_STATUS, status); + } + sequence = SEQ_SEND_RETR; + return true; +} + +bool FtpNegotiationCommand::sendRetr() { + ftp->sendRetr(); + sequence = SEQ_RECV_RETR; + return false; +} + +bool FtpNegotiationCommand::recvRetr() { + int status = ftp->receiveResponse(); + if(status == 0) { + return false; + } + if(status != 150) { + throw new DlAbortEx(EX_BAD_STATUS, status); + } + if(e->option->get("ftp_pasv_enabled") != "true") { + assert(serverSocket); + dataSocket = serverSocket->acceptConnection(); + } + sequence = SEQ_NEGOTIATION_COMPLETED; + + return false; +} + +bool FtpNegotiationCommand::processSequence(const Segment& segment) { + bool doNextSequence = true; + switch(sequence) { + case SEQ_RECV_GREETING: + return recvGreeting(); + case SEQ_SEND_USER: + return sendUser(); + case SEQ_RECV_USER: + return recvUser(); + case SEQ_SEND_PASS: + return sendPass(); + case SEQ_RECV_PASS: + return recvPass(); + case SEQ_SEND_TYPE: + return sendType(); + case SEQ_RECV_TYPE: + return recvType(); + case SEQ_SEND_CWD: + return sendCwd(); + case SEQ_RECV_CWD: + return recvCwd(); + case SEQ_SEND_SIZE: + return sendSize(); + case SEQ_RECV_SIZE: + return recvSize(); + case SEQ_SEND_PORT: + return sendPort(); + case SEQ_RECV_PORT: + return recvPort(); + case SEQ_SEND_PASV: + return sendPasv(); + case SEQ_RECV_PASV: + return recvPasv(); + case SEQ_SEND_REST_PASV: + return sendRestPasv(segment); + case SEQ_SEND_REST: + return sendRest(segment); + case SEQ_RECV_REST: + return recvRest(); + case SEQ_SEND_RETR: + return sendRetr(); + case SEQ_RECV_RETR: + return recvRetr(); + default: + abort(); + } + return doNextSequence; +} diff --git a/src/FtpNegotiationCommand.h b/src/FtpNegotiationCommand.h new file mode 100644 index 00000000..29e2c0e6 --- /dev/null +++ b/src/FtpNegotiationCommand.h @@ -0,0 +1,87 @@ +/* */ +#ifndef _D_FTP_NEGOTIATION_COMMAND_H_ +#define _D_FTP_NEGOTIATION_COMMAND_H_ + +#include "AbstractCommand.h" +#include "FtpConnection.h" + +class FtpNegotiationCommand : public AbstractCommand { +private: + enum Seq { + SEQ_RECV_GREETING, + SEQ_SEND_USER, + SEQ_RECV_USER, + SEQ_SEND_PASS, + SEQ_RECV_PASS, + SEQ_SEND_TYPE, + SEQ_RECV_TYPE, + SEQ_SEND_CWD, + SEQ_RECV_CWD, + SEQ_SEND_SIZE, + SEQ_RECV_SIZE, + SEQ_SEND_PORT, + SEQ_RECV_PORT, + SEQ_SEND_PASV, + SEQ_RECV_PASV, + SEQ_SEND_REST_PASV, + SEQ_SEND_REST, + SEQ_RECV_REST, + SEQ_SEND_RETR, + SEQ_RECV_RETR, + SEQ_NEGOTIATION_COMPLETED, + SEQ_RETRY + }; + bool recvGreeting(); + bool sendUser(); + bool recvUser(); + bool sendPass(); + bool recvPass(); + bool sendType(); + bool recvType(); + bool sendCwd(); + bool recvCwd(); + bool sendSize(); + bool recvSize(); + bool sendPort(); + bool recvPort(); + bool sendPasv(); + bool recvPasv(); + bool sendRest(const Segment& segment); + bool sendRestPasv(const Segment& segment); + bool recvRest(); + bool sendRetr(); + bool recvRetr(); + bool processSequence(const Segment& segment); + + Socket* dataSocket; + Socket* serverSocket; + int sequence; + FtpConnection* ftp; +protected: + bool executeInternal(Segment segment); +public: + FtpNegotiationCommand(int cuid, Request* req, DownloadEngine* e, Socket* s); + ~FtpNegotiationCommand(); +}; + +#endif // _D_FTP_NEGOTIATION_COMMAND_H_ diff --git a/src/FtpTunnelRequestCommand.cc b/src/FtpTunnelRequestCommand.cc new file mode 100644 index 00000000..f103f7ce --- /dev/null +++ b/src/FtpTunnelRequestCommand.cc @@ -0,0 +1,41 @@ +/* */ +#include "FtpTunnelRequestCommand.h" +#include "FtpTunnelResponseCommand.h" +#include "HttpConnection.h" + +FtpTunnelRequestCommand::FtpTunnelRequestCommand(int cuid, Request* req, DownloadEngine* e, Socket* s):AbstractCommand(cuid, req, e, s) { + setReadCheckSocket(NULL); + setWriteCheckSocket(NULL); +} + +FtpTunnelRequestCommand::~FtpTunnelRequestCommand() {} + +bool FtpTunnelRequestCommand::executeInternal(Segment segment) { + socket->setBlockingMode(); + HttpConnection httpConnection(cuid, socket, req, e->option, e->logger); + httpConnection.sendProxyRequest(); + + FtpTunnelResponseCommand* command = new FtpTunnelResponseCommand(cuid, req, e, socket); + e->commands.push(command); + return true; +} diff --git a/src/FtpTunnelRequestCommand.h b/src/FtpTunnelRequestCommand.h new file mode 100644 index 00000000..817f1c9d --- /dev/null +++ b/src/FtpTunnelRequestCommand.h @@ -0,0 +1,35 @@ +/* */ +#ifndef _D_FTP_TUNNEL_REQUEST_COMMAND_H_ +#define _D_FTP_TUNNEL_REQUEST_COMMAND_H_ + +#include "AbstractCommand.h" + +class FtpTunnelRequestCommand : public AbstractCommand { +protected: + bool executeInternal(Segment segment); +public: + FtpTunnelRequestCommand(int cuid, Request* req, DownloadEngine* e, Socket* s); + ~FtpTunnelRequestCommand(); +}; + +#endif // _D_FTP_TUNNEL_REQUEST_COMMAND_H_ diff --git a/src/FtpTunnelResponseCommand.cc b/src/FtpTunnelResponseCommand.cc new file mode 100644 index 00000000..7009310c --- /dev/null +++ b/src/FtpTunnelResponseCommand.cc @@ -0,0 +1,49 @@ +/* */ +#include "FtpTunnelResponseCommand.h" +#include "FtpNegotiationCommand.h" +#include "DlRetryEx.h" +#include "message.h" + +FtpTunnelResponseCommand::FtpTunnelResponseCommand(int cuid, Request* req, DownloadEngine* e, Socket* s):AbstractCommand(cuid, req, e, s) { + http = new HttpConnection(cuid, socket, req, e->option, e->logger); +} + +FtpTunnelResponseCommand::~FtpTunnelResponseCommand() { + delete http; +} + +bool FtpTunnelResponseCommand::executeInternal(Segment segment) { + HttpHeader headers; + int status = http->receiveResponse(headers); + if(status == 0) { + // we didn't receive all of headers yet. + e->commands.push(this); + return false; + } + if(status != 200) { + throw new DlRetryEx(EX_PROXY_CONNECTION_FAILED); + } + FtpNegotiationCommand* command = new FtpNegotiationCommand(cuid, req, e, socket); + e->commands.push(command); + return true; +} diff --git a/src/FtpTunnelResponseCommand.h b/src/FtpTunnelResponseCommand.h new file mode 100644 index 00000000..eeba75ac --- /dev/null +++ b/src/FtpTunnelResponseCommand.h @@ -0,0 +1,39 @@ +/* */ +#ifndef _D_FTP_TUNNEL_RESPONSE_COMMAND_H_ +#define _D_FTP_TUNNEL_RESPONSE_COMMAND_H_ + +#include "AbstractCommand.h" +#include "HttpConnection.h" + +class FtpTunnelResponseCommand : public AbstractCommand { +private: + HttpConnection* http; +protected: + bool executeInternal(Segment segment); +public: + FtpTunnelResponseCommand(int cuid, Request* req, DownloadEngine* e, Socket* s); + ~FtpTunnelResponseCommand(); +}; + +#endif // _D_FTP_TUNNEL_RESPONSE_COMMAND_H_ + diff --git a/src/HttpHeader.cc b/src/HttpHeader.cc new file mode 100644 index 00000000..eb80cf5b --- /dev/null +++ b/src/HttpHeader.cc @@ -0,0 +1,66 @@ +/* */ +#include "HttpHeader.h" + +void HttpHeader::put(const string& name, const string& value) { + multimap::value_type vt(name, value); + table.insert(vt); +} + +bool HttpHeader::defined(const string& name) const { + return table.count(name) == 1; +} + +string HttpHeader::getFirst(const string& name) const { + multimap::const_iterator itr = table.find(name); + if(itr == table.end()) { + return ""; + } else { + return (*itr).second; + } +} + +vector HttpHeader::get(const string& name) const { + vector v; + for(multimap::const_iterator itr = table.find(name); itr != table.end(); itr++) { + v.push_back((*itr).second); + } + return v; +} + +int HttpHeader::getFirstAsInt(const string& name) const { + multimap::const_iterator itr = table.find(name); + if(itr == table.end()) { + return 0; + } else { + return (int)strtol((*itr).second.c_str(), NULL, 10); + } +} + +long long int HttpHeader::getFirstAsLLInt(const string& name) const { + multimap::const_iterator itr = table.find(name); + if(itr == table.end()) { + return 0; + } else { + return strtoll((*itr).second.c_str(), NULL, 10); + } +} diff --git a/src/HttpHeader.h b/src/HttpHeader.h new file mode 100644 index 00000000..3bcaa479 --- /dev/null +++ b/src/HttpHeader.h @@ -0,0 +1,46 @@ +/* */ +#ifndef _D_HTTP_HEADER_H_ +#define _D_HTTP_HEADER_H_ + +#include +#include +#include + +using namespace std; + +class HttpHeader { +private: + multimap table; +public: + HttpHeader() {} + ~HttpHeader() {} + + void put(const string& name, const string& value); + bool defined(const string& name) const; + string getFirst(const string& name) const; + vector get(const string& name) const; + int getFirstAsInt(const string& name) const; + long long int getFirstAsLLInt(const string& name) const; +}; + +#endif // _D_HTTP_HEADER_H_