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)