Go to the documentation of this file.
129 void start()
override;
194 #define CTRL_BUFLEN 16*1024
346 old_filepath(nullptr),
368 debugs(9, 3, entry->url());
372 "control channel " << ctrl.conn);
401 debugs(9, 4,
"login=" << login <<
", escaped=" << escaped);
402 debugs(9, 9,
"IN : login=" << login <<
", escaped=" << escaped <<
", user=" << user <<
", password=" << password);
408 debugs(9, 2,
"WARNING: Ignoring FTP credentials that start with a NUL character");
419 const SBuf userName = login.
substr(0, colonPos);
422 debugs(9, 9,
"found user=" << userName <<
' ' <<
423 (upto != userName.
length() ?
", truncated-to=" :
", length=") << upto <<
424 ", escaped=" << escaped);
427 debugs(9, 9,
"found user=" << user <<
" (" << strlen(user) <<
") unescaped.");
437 debugs(9, 9,
"found password=" << pass <<
" " <<
438 (upto != pass.
length() ?
", truncated-to=" :
", length=") << upto <<
439 ", escaped=" << escaped);
444 debugs(9, 9,
"found password=" << password <<
" (" << strlen(password) <<
") unescaped.");
447 debugs(9, 9,
"OUT: login=" << login <<
", escaped=" << escaped <<
", user=" << user <<
", password=" << password);
454 debugs(9, 5,
"The control connection to the remote end is closed");
464 const char *note = entry->url();
473 debugs(9, 3,
"Unconnected data socket created on " << conn);
476 conn->
tos = ctrl.conn->tos;
477 conn->
nfmark = ctrl.conn->nfmark;
483 data.opened(conn, dataCloser());
484 switchTimeoutToDataChannel();
490 if (SENT_PASV == state) {
492 flags.pasv_supported =
false;
496 dataConnWait.cancel(
"timeout");
505 "Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
506 "Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
514 for (i = 0; i < 12; ++i)
515 if (!strcasecmp(buf,
Month[i]))
531 #define MAX_TOKENS 64
538 struct FtpLineToken {
539 char *token =
nullptr;
544 static char tbuf[128];
545 char *xbuf =
nullptr;
546 static int scan_ftp_initialized = 0;
547 static regex_t scan_ftp_integer;
548 static regex_t scan_ftp_time;
549 static regex_t scan_ftp_dostime;
550 static regex_t scan_ftp_dosdate;
552 if (!scan_ftp_initialized) {
553 scan_ftp_initialized = 1;
554 regcomp(&scan_ftp_integer,
"^[0123456789]+$", REG_EXTENDED | REG_NOSUB);
555 regcomp(&scan_ftp_time,
"^[0123456789:]+$", REG_EXTENDED | REG_NOSUB);
556 regcomp(&scan_ftp_dosdate,
"^[0123456789]+-[0123456789]+-[0123456789]+$", REG_EXTENDED | REG_NOSUB);
557 regcomp(&scan_ftp_dostime,
"^[0123456789]+:[0123456789]+[AP]M$", REG_EXTENDED | REG_NOSUB | REG_ICASE);
581 tokens[n_tokens].pos = t - xbuf;
588 for (i = 3; i < n_tokens - 2; ++i) {
597 if (regexec(&scan_ftp_integer,
size, 0,
nullptr, 0) != 0)
600 if (regexec(&scan_ftp_integer, day, 0,
nullptr, 0) != 0)
603 if (regexec(&scan_ftp_time, year, 0,
nullptr, 0) != 0)
606 const auto *copyFrom = buf +
tokens[i].pos;
609 auto dateSize = snprintf(tbuf,
sizeof(tbuf),
"%s %2s %5s", month, day, year);
610 bool isTypeA = (dateSize == 12) && (strncmp(copyFrom, tbuf, dateSize) == 0);
613 dateSize = snprintf(tbuf,
sizeof(tbuf),
"%s %2s %-5s", month, day, year);
614 bool isTypeB = (dateSize == 12 || dateSize == 11) && (strncmp(copyFrom, tbuf, dateSize) == 0);
617 if (isTypeA || isTypeB) {
620 const auto finalDateSize = snprintf(tbuf,
sizeof(tbuf),
"%s %2s %5s", month, day, year);
621 assert(finalDateSize >= 0);
625 copyFrom = buf +
tokens[i + 2].pos + strlen(
tokens[i + 2].token);
627 while (strchr(
w_space, *copyFrom))
638 if (strchr(
w_space, *copyFrom))
644 if (p->
type ==
'l' && (t = strstr(p->
name,
" -> "))) {
657 regexec(&scan_ftp_dosdate,
tokens[0].token, 0,
nullptr, 0) == 0 &&
658 regexec(&scan_ftp_dostime,
tokens[1].token, 0,
nullptr, 0) == 0) {
659 if (!strcasecmp(
tokens[2].token,
"<dir>")) {
666 snprintf(tbuf,
sizeof(tbuf),
"%s %s",
tokens[0].token,
tokens[1].token);
669 if (p->
type ==
'd') {
686 const char *ct = buf + 1;
691 int l = strcspn(ct,
",");
705 p->
size = atoi(ct + 1);
709 tm = (time_t) strtol(ct + 1, &tmp, 0);
717 *(strstr(p->
date,
"\n")) =
'\0';
739 ct = strstr(ct,
",");
758 for (i = 0; i < n_tokens; ++i)
770 debugs(9, 7,
"line={" << line <<
"}");
772 if (strlen(line) > 1024) {
773 html <<
"<tr><td colspan=\"5\">" << line <<
"</td></tr>\n";
778 if (flags.dir_slash && dirpath && typecode !=
'D') {
785 html <<
"<tr class=\"entry\"><td colspan=\"5\">" << line <<
"</td></tr>\n";
788 for (p = line; *p &&
xisspace(*p); ++p);
790 flags.listformat_unknown = 1;
795 if (!strcmp(parts->
name,
".") || !strcmp(parts->
name,
"..")) {
811 switch (parts->
type) {
814 icon.
appendf(
"<img border=\"0\" src=\"%s\" alt=\"%-6s\">",
821 icon.
appendf(
"<img border=\"0\" src=\"%s\" alt=\"%-6s\">",
836 icon.
appendf(
"<img border=\"0\" src=\"%s\" alt=\"%-6s\">",
839 chdir.
appendf(
"<a href=\"%s/;type=d\"><img border=\"0\" src=\"%s\" "
840 "alt=\"[DIR]\"></a>",
848 icon.
appendf(
"<img border=\"0\" src=\"%s\" alt=\"%-6s\">",
856 if (parts->
type !=
'd') {
859 "alt=\"[VIEW]\"></a>",
865 "alt=\"[DOWNLOAD]\"></a>",
871 html <<
"<tr class=\"entry\">"
872 "<td class=\"icon\"><a href=\"" << href <<
"\">" << icon <<
"</a></td>"
873 "<td class=\"filename\"><a href=\"" << href <<
"\">" <<
html_quote(
text.
c_str()) <<
"</a></td>"
874 "<td class=\"date\">" << parts->
date <<
"</td>"
875 "<td class=\"size\">" <<
size <<
"</td>"
876 "<td class=\"actions\">" << chdir << view << download << link <<
"</td>"
886 char *buf = data.readBuf->content();
893 size_t len = data.readBuf->contentSize();
896 debugs(9, 3,
"no content to parse for " << entry->url() );
903 sbuf = (
char *)
xmalloc(len + 1);
905 end = sbuf + len - 1;
907 while (*end !=
'\r' && *end !=
'\n' && end > sbuf)
912 debugs(9, 3,
"usable = " << usable <<
" of " << len <<
" bytes.");
915 if (buf[0] ==
'\0' && len == 1) {
916 debugs(9, 3,
"NIL ends data from " << entry->url() <<
" transfer problem?");
917 data.readBuf->consume(len);
919 debugs(9, 3,
"didn't find end for " << entry->url());
926 debugs(9, 3, (
unsigned long int)len <<
" bytes to play with");
931 s += strspn(s,
crlf);
933 for (; s < end; s += strcspn(s,
crlf), s += strspn(s,
crlf)) {
934 debugs(9, 7,
"s = {" << s <<
"}");
935 linelen = strcspn(s,
crlf) + 1;
945 debugs(9, 7,
"{" << line <<
"}");
947 if (!strncmp(line,
"total", 5))
954 if (htmlifyListEntry(line, html)) {
962 data.readBuf->consume(usable);
978 if (!flags.http_header_sent && data.readBuf->contentSize() >= 0 && !flags.isdir)
979 appendSuccessHeader();
986 abortAll(
"entry aborted after calling appendSuccessHeader()");
992 if (adaptationAccessCheckPending) {
993 debugs(9, 3,
"returning from Ftp::Gateway::processReplyBody due to adaptationAccessCheckPending");
1000 if (!flags.listing) {
1005 maybeReadVirginBody();
1007 }
else if (
const auto csize = data.readBuf->contentSize()) {
1008 writeReplyBody(data.readBuf->content(), csize);
1009 debugs(9, 5,
"consuming " << csize <<
" bytes of readBuf");
1010 data.readBuf->consume(csize);
1015 maybeReadVirginBody();
1040 #if HAVE_AUTH_MODULE_BASIC
1043 if (!auth.isEmpty()) {
1044 flags.authenticated = 1;
1045 loginParser(auth,
false);
1053 loginParser(request->url.userInfo(),
true);
1065 if (strcmp(user,
"anonymous") == 0 && !flags.tried_auth_anonymous) {
1067 flags.tried_auth_anonymous=1;
1069 }
else if (!flags.tried_auth_nopass) {
1071 flags.tried_auth_nopass=1;
1087 static const SBuf middle(
";type=");
1088 const auto typeSpecStart = request->url.path().find(middle);
1090 const auto fullPath = request->url.path();
1091 const auto typecodePos = typeSpecStart + middle.
length();
1092 typecode = (typecodePos < fullPath.length()) ?
1093 static_cast<char>(
xtoupper(fullPath[typecodePos])) :
'\0';
1094 request->url.path(fullPath.substr(0, typeSpecStart));
1097 int l = request->url.path().length();
1103 flags.need_base_href = 1;
1104 }
else if (!request->url.path().cmp(
"/%2f/")) {
1108 }
else if ((l >= 1) && (request->url.path()[l-1] ==
'/')) {
1115 flags.dir_slash = 1;
1122 title_url =
"ftp://";
1124 if (strcmp(user,
"anonymous")) {
1125 title_url.append(user);
1126 title_url.append(
"@");
1131 title_url.
append(authority);
1132 title_url.
append(request->url.absolutePath());
1134 base_href =
"ftp://";
1136 if (strcmp(user,
"anonymous") != 0) {
1147 base_href.
append(authority);
1148 base_href.
append(request->url.path());
1155 if (!checkAuth(&request->header)) {
1157 SBuf realm(ftpRealm());
1158 const auto reply = ftpAuthRequired(request.getRaw(), realm, fwd->al);
1159 entry->replaceHttpReply(reply);
1166 debugs(9, 5,
"FD " << (ctrl.conn ? ctrl.conn->fd : -1) <<
" : host=" << request->url.host() <<
1167 ", path=" << request->url.absolutePath() <<
", user=" << user <<
", passwd=" << password);
1178 if (ctrl.message ==
nullptr)
1185 cwd_message.append(
'\n');
1186 cwd_message.append(w->key);
1210 }
else if (code == 120) {
1230 if ((state == SENT_USER || state == SENT_PASS) && ctrl.replycode >= 400) {
1231 if (ctrl.replycode == 421 || ctrl.replycode == 426) {
1234 }
else if (ctrl.replycode >= 430 && ctrl.replycode <= 439) {
1237 }
else if (ctrl.replycode >= 530 && ctrl.replycode <= 539) {
1251 failed(
ERR_NONE, ctrl.replycode, err);
1257 #if HAVE_AUTH_MODULE_BASIC
1260 SBuf realm(ftpRealm());
1265 entry->replaceHttpReply(newrep);
1275 realm.
appendf(
"FTP %s ", user);
1277 realm.
append(
"unknown", 7);
1279 realm.
append(request->url.host());
1280 const auto &rport = request->url.port();
1281 if (rport && *rport != 21)
1282 realm.
appendf(
" port %hu", *rport);
1312 }
else if (code == 331) {
1335 debugs(9, 3,
"code=" << code);
1399 debugs(9, 3,
"code=" << code);
1409 p += strcspn(p,
"/");
1445 debugs(9, 3,
"the final component was a directory");
1457 debugs(9, 3,
"final component is probably a file");
1466 char *path =
nullptr;
1476 if (!strcmp(path,
"..") || !strcmp(path,
"/")) {
1495 if (code >= 200 && code < 300) {
1522 char *path =
nullptr;
1529 debugs(9, 3,
"with path=" << path);
1541 debugs(9, 3,
"path " << path <<
", code " << code);
1545 }
else if (code == 550) {
1568 debugs(9, 3,
"Directory path did not end in /");
1598 }
else if (code < 0) {
1638 debugs(9, 2,
"SIZE reported " <<
1643 }
else if (code < 0) {
1693 debugs(9, 5,
"handling HEAD response");
1695 appendSuccessHeader();
1703 abortAll(
"entry aborted while processing HEAD");
1708 if (adaptationAccessCheckPending) {
1709 debugs(9,3,
"returning due to adaptationAccessCheckPending");
1736 dataConnWait.finish();
1739 debugs(9, 2,
"Failed to connect. Retrying via another method.");
1743 writeCommand(
"ABOR\r\n");
1750 data.opened(io.
conn, dataCloser());
1758 if (ftpState->
data.
conn !=
nullptr) {
1768 debugs(9, 5,
"The control connection to the remote end is closed");
1787 &
on,
sizeof(
on)) == -1) {
1796 temp->local.port(0);
1810 debugs(9,
DBG_IMPORTANT,
"FTP does not allow PORT method after 'EPSV ALL' has been sent.");
1835 struct addrinfo *AI =
nullptr;
1837 unsigned char *addrptr = (
unsigned char *) &((
struct sockaddr_in*)AI->ai_addr)->sin_addr;
1838 unsigned char *portptr = (
unsigned char *) &((
struct sockaddr_in*)AI->ai_addr)->sin_port;
1840 addrptr[0], addrptr[1], addrptr[2], addrptr[3],
1841 portptr[0], portptr[1]);
1856 debugs(9, 3,
"PORT not supported by remote end");
1871 debugs(9, 3,
"EPRT not supported by remote end");
1889 debugs(9, 5,
"The control connection to the remote end is closed");
1894 data.listenConn->close();
1895 data.listenConn =
nullptr;
1903 abortAll(
"entry aborted when accepting data conn");
1904 data.listenConn->close();
1905 data.listenConn =
nullptr;
1912 data.listenConn =
nullptr;
1932 "ERROR: FTP data connection from unexpected server (" <<
1934 data.conn->remote <<
" or " << ctrl.conn->remote);
1946 data.opened(io.
conn, dataCloser());
1949 debugs(9, 3,
"Connected data socket on " <<
1950 io.
conn <<
". FD table says: " <<
1951 "ctrl-peer= " <<
fd_table[ctrl.conn->fd].ipaddr <<
", " <<
1952 "data-peer= " <<
fd_table[data.conn->fd].ipaddr);
1954 assert(haveControlChannel(
"ftpAcceptDataConnection"));
1955 assert(ctrl.message ==
nullptr);
1992 if (ftpState->
filepath !=
nullptr) {
2017 int code = ctrl.replycode;
2021 if (!originalRequest()->body_pipe) {
2022 debugs(9, 3,
"zero-size STOR?");
2023 state = WRITING_DATA;
2028 if (!startRequestBodyFlow()) {
2034 debugs(9, 3,
"starting data transfer");
2035 switchTimeoutToDataChannel();
2036 sendMoreRequestBody();
2037 fwd->dontRetry(
true);
2038 state = WRITING_DATA;
2039 debugs(9, 3,
"writing data channel");
2040 }
else if (code == 150) {
2042 debugs(9, 3,
"ftpReadStor: accepting data channel");
2043 listenForDataChannel(data.conn);
2045 debugs(9,
DBG_IMPORTANT,
"ERROR: Unexpected reply code "<< std::setfill(
'0') << std::setw(3) << code);
2067 if (restart_offset > 0)
2070 if (!request->range)
2079 int64_t desired_offset = request->range->lowestOffset(theSize);
2081 if (desired_offset <= 0)
2084 if (desired_offset >= theSize)
2087 restart_offset = desired_offset;
2101 }
else if (code > 0) {
2102 debugs(9, 3,
"REST not supported");
2163 }
else if (code == 150) {
2203 }
else if (code == 150) {
2206 }
else if (code >= 300) {
2226 entry->lock(
"Ftp::Gateway");
2232 ctrl.message =
nullptr;
2235 entry->unlock(
"Ftp::Gateway");
2244 if (code == 226 || code == 250) {
2265 debugs(9, 3,
"ftpState=" <<
this);
2275 if (!(code == 226 || code == 250)) {
2344 if (old_request !=
nullptr) {
2354 setCurrentOffset(0);
2360 if (old_request ==
nullptr) {
2361 old_request = ctrl.last_command;
2362 ctrl.last_command =
nullptr;
2363 old_reply = ctrl.last_reply;
2364 ctrl.last_reply =
nullptr;
2366 if (pathcomps ==
nullptr && filepath !=
nullptr)
2367 old_filepath =
xstrdup(filepath);
2377 const bool slashHack = ftpState->
request->
url.
path().caseCmp(
"/%2f", 4)==0;
2382 " reply code " << code <<
"flags(" <<
2386 "mdtm=" << ftpState->
mdtm <<
", size=" << ftpState->
theSize <<
2387 "slashhack=" << (slashHack?
"T":
"F"));
2395 switch (ftpState->
state) {
2411 ftpState->
failed(error_code, 0, ftperr);
2413 HttpReply *newrep = ftperr->BuildHttpReply();
2430 if (ctrl.replycode > 500) {
2433 }
else if (ctrl.replycode == 421) {
2442 if (ctrl.replycode == 550) {
2465 debugs(9, 5,
"ftpState (" << ftpState <<
") is valid!");
2467 if (code == 226 || code == 250) {
2470 }
else if (code == 227) {
2504 if (flags.http_header_sent)
2509 flags.http_header_sent = 1;
2511 assert(entry->isEmpty());
2515 SBuf urlPath = request->url.path();
2516 auto t = urlPath.
rfind(
'/');
2519 const char *mime_type =
nullptr;
2520 const char *mime_enc =
nullptr;
2523 mime_type =
"text/html";
2528 mime_type =
"application/octet-stream";
2534 mime_type =
"text/plain";
2547 if (0 == getCurrentOffset()) {
2550 }
else if (theSize < getCurrentOffset()) {
2558 " current offset=" << getCurrentOffset() <<
2559 ", but theSize=" << theSize <<
2560 ". assuming full content response");
2565 range_spec.
offset = getCurrentOffset();
2566 range_spec.
length = theSize - getCurrentOffset();
2576 setVirginReply(reply);
2577 adaptOrFinalizeReply();
2590 if (flags.authenticated ||
2591 getCurrentOffset() ||
2602 #if HAVE_AUTH_MODULE_BASIC
2618 static const SBuf nil;
2625 }
else if (!request->
url.
path().startsWith(newbuf)) {
2640 debugs(9, 5,
"writing " << dataLength <<
" bytes to the reply");
2641 addVirginReplyBody(dataToWrite, dataLength);
2653 if (fwd ==
nullptr || flags.completed_forwarding) {
2654 debugs(9, 3,
"avoid double-complete on FD " <<
2655 (ctrl.conn ? ctrl.conn->fd : -1) <<
", Data FD " << (data.conn ? data.conn->fd : -1) <<
2656 ", this " <<
this <<
", fwd " << fwd);
2660 flags.completed_forwarding =
true;
2673 if (doneWithServer())
2678 debugs(9,
DBG_IMPORTANT,
"WARNING: FTP Server Control channel is closed, but Data channel still active.");
2679 debugs(9, 2, caller_name <<
": attempted on a closed FTP channel.");
2690 return !doneWithServer();
static void ftpTrySlashHack(Ftp::Gateway *ftpState)
const char * xstrerr(int error)
void processReplyBody() override
void handleRequestBodyProducerAborted() override
void * xcalloc(size_t n, size_t sz)
size_type find(char c, size_type startPos=0) const
void wordlistDestroy(wordlist **list)
destroy a wordlist
AnyP::Uri url
the request URI
bool makePublic(const KeyScope keyScope=ksDefault)
static FTPSM ftpReadTransferDone
void maybeReadVirginBody() override
read response data from the network
void connectDataChannel()
void writeCommand(const char *buf)
std::optional< SBuf > decodedRequestUriPath() const
absolute request URI path after successful decoding of all pct-encoding sequences
bool pasv_supported
PASV command is allowed.
static void ftpOpenListenSocket(Ftp::Gateway *ftpState, int fallback)
HttpReply * BuildHttpReply(void)
virtual void handleRequestBodyProducerAborted()=0
void error(char *format,...)
AccessLogEntryPointer al
info for the future access.log entry
@ ERR_CACHE_ACCESS_DENIED
bool tried_auth_nopass
auth tried username with no password already.
void dataClosed(const CommCloseCbParams &io) override
handler called by Comm when FTP data channel is closed unexpectedly
struct ErrorState::@47 ftp
void init(mb_size_t szInit, mb_size_t szMax)
static HttpReply * ftpAuthRequired(HttpRequest *request, SBuf &realm, AccessLogEntry::Pointer &)
bool htmlifyListEntry(const char *line, PackableStream &)
void SBufToCstring(char *d, const SBuf &s)
void handleControlReply() override
int checkAuth(const HttpHeader *req_hdr)
static void FreeAddr(struct addrinfo *&ai)
void loginParser(const SBuf &login, bool escaped)
char * xstrncpy(char *dst, const char *src, size_t n)
void detailError(const ErrorDetail::Pointer &dCode)
set error type-specific detail code
int cbdataReferenceValid(const void *p)
bool IsConnOpen(const Comm::ConnectionPointer &conn)
#define rfc1738_escape(x)
virtual void failed(err_type error=ERR_NONE, int xerrno=0, ErrorState *ftperr=nullptr)
handle a fatal transaction error, closing the control connection
void replaceHttpReply(const HttpReplyPointer &, const bool andStartWriting=true)
void * memAllocate(mem_type)
Allocate one element from the typed pool.
static FTPSM ftpSendMkdir
static FTPSM ftpRestOrList
virtual void haveParsedReplyHeaders()
called when we have final (possibly adapted) reply headers; kids extend
char * wordlistChopHead(wordlist **wl)
int xerrno
The last errno to occur. non-zero if flag is Comm::COMM_ERROR.
SBuf substr(size_type pos, size_type n=npos) const
FTP client functionality shared among FTP Gateway and Relay clients.
virtual void completeForwarding()
void() StateMethod(Ftp::Gateway *)
CBDATA_NAMESPACED_CLASS_INIT(Ftp, Gateway)
void comm_open_listener(int sock_type, int proto, Comm::ConnectionPointer &conn, const char *note)
virtual bool haveControlChannel(const char *caller_name) const
size_type rfind(char c, size_type endPos=npos) const
bool handlePasvReply(Ip::Address &remoteAddr)
mb_size_t contentSize() const
available data size
static FTPSM ftpReadMkdir
void start() override
called by AsyncStart; do not call directly
static char cbuf[CTRL_BUFLEN]
bool completed_forwarding
void rfc1738_unescape(char *url)
#define SQUIDSBUFPRINT(s)
virtual void handleControlReply()
virtual void dataClosed(const CommCloseCbParams &io)
handler called by Comm when FTP data channel is closed unexpectedly
MemBlob::size_type size_type
void append(char const *buf, int len)
static FTPSM ftpReadWelcome
HttpRequestPointer request
char * html_quote(const char *string)
void appendSuccessHeader()
SBuf text("GET http://resource.com/path HTTP/1.1\r\n" "Host: resource.com\r\n" "Cookie: laijkpk3422r j1noin \r\n" "\r\n")
#define EBIT_TEST(flag, bit)
bool handleEpsvReply(Ip::Address &remoteAddr)
int xsetsockopt(int socketFd, int level, int option, const void *value, socklen_t valueLength)
POSIX setsockopt(2) equivalent.
void timeout(const CommTimeoutCbParams &io) override
read timeout handler
Comm::ConnectionPointer conn
@ srcFtp
ftp_port or FTP server
void close()
planned close: removes the close handler and calls comm_close
void ftpAcceptDataConnection(const CommAcceptCbParams &io)
static std::optional< SBuf > Decode(const SBuf &)
bool tried_auth_anonymous
auth has tried to use anonymous credentials already.
bool authenticated
authentication success
bool mayReadVirginReplyBody() const override
whether we may receive more virgin response body bytes
Comm::Flag flag
comm layer result status.
static FTPSM ftpTraverseDirectory
const AnyP::UriScheme & getScheme() const
#define Assure(condition)
#define JobCallback(dbgSection, dbgLevel, Dialer, job, method)
Convenience macro to create a Dialer-based job callback.
Comm::ConnectionPointer conn
channel descriptor
int64_t strtoll(const char *nptr, char **endptr, int base)
size_type length() const
Returns the number of bytes stored in SBuf.
char * xstrndup(const char *s, size_t n)
SBuf & append(const SBuf &S)
void completeForwarding() override
DataChannel data
FTP data channel state.
static FTPSM ftpSendPassive
bool mimeGetViewOption(const char *fn)
static const size_type npos
void markParsedVirginReplyAsWhole(const char *reasonWeAreSure)
uint32_t sources
The message sources.
void writeReplyBody(const char *, size_t len)
static void ftpListPartsFree(ftpListParts **parts)
static const char * Month[]
void hackShortcut(StateMethod *nextState)
void clear()
remove the close handler, leave connection open
static const SBuf & SlashPath()
the static '/' default URL-path
Comm::ConnectionPointer listenConn
const char * mimeGetContentType(const char *fn)
virtual Http::StatusCode failedHttpStatus(err_type &error)
MemBuf listing
FTP directory listing in HTML format.
void dataChannelConnected(const CommConnectCbParams &io) override
void getAddrInfo(struct addrinfo *&ai, int force=AF_UNSPEC) const
const SBuf & UrlWith2f(HttpRequest *)
static ftpListParts * ftpListParseParts(const char *buf, struct Ftp::GatewayFlags flags)
void processHeadResponse()
void httpHeaderAddContRange(HttpHeader *, HttpHdrRangeSpec, int64_t)
char * content()
start of the added data
static int is_month(const char *buf)
void memFree(void *, int type)
Free a element allocated by memAllocate()
void StartGateway(FwdState *const fwdState)
A new FTP Gateway job.
const char * mimeGetContentEncoding(const char *fn)
void reset(char const *str)
struct SquidConfig::@92 Ftp
void listenForDataChannel(const Comm::ConnectionPointer &conn)
create a data channel acceptor and start listening.
Http::StatusCode failedHttpStatus(err_type &error) override
void completedListing(void)
void release(const bool shareable=false)
void haveParsedReplyHeaders() override
called when we have final (possibly adapted) reply headers; kids extend
time_t ParseIso3307(const char *)
Convert from ISO 3307 style time: YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx.
char * rfc1738_do_escape(const char *url, int flags)
int64_t getCurrentOffset() const
CtrlChannel ctrl
FTP control channel state.
const char * mimeGetIconURL(const char *fn)
void setHeaders(Http::StatusCode status, const char *reason, const char *ctype, int64_t clen, time_t lmt, time_t expires)
bool mimeGetDownloadOption(const char *fn)
SBuf & appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
#define rfc1738_escape_part(x)
const char * wordlistAdd(wordlist **list, const char *key)
const SBuf & effectiveRequestUri() const
RFC 7230 section 5.5 - Effective Request URI.
virtual void timeout(const CommTimeoutCbParams &io)
read timeout handler
void host(const char *src)
static FTPSM ftpSendReply
HttpRequestPointer request
#define debugs(SECTION, LEVEL, CONTENT)
void setCurrentOffset(int64_t offset)
void start() override
called by AsyncStart; do not call directly
void switchTimeoutToDataChannel()
size_type copy(char *dest, size_type n) const
char mimeGetTransferMode(const char *fn)
static FTPSM ftpWriteTransferDone
bool epsv_all_sent
EPSV ALL has been used. Must abort on failures.
static void Start(const Pointer &job)