]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/clients/FtpClient.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / clients / FtpClient.cc
index 00caa63abbb759c817e0835c31e64aa264eddd8b..aa8e1ca5428ca66466b95c26f4818b5d0cd2db5a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
  *
  * Squid software is distributed under GPLv2+ license and includes
  * contributions from numerous individuals and organizations.
@@ -19,6 +19,7 @@
 #include "errorpage.h"
 #include "fd.h"
 #include "ftp/Parsing.h"
+#include "http/Stream.h"
 #include "ip/tools.h"
 #include "SquidConfig.h"
 #include "SquidString.h"
@@ -242,13 +243,23 @@ Ftp::Client::doneWithServer() const
 }
 
 void
-Ftp::Client::failed(err_type error, int xerrno)
+Ftp::Client::failed(err_type error, int xerrno, ErrorState *err)
 {
     debugs(9, 3, "entry-null=" << (entry?entry->isEmpty():0) << ", entry=" << entry);
 
     const char *command, *reply;
-    const Http::StatusCode httpStatus = failedHttpStatus(error);
-    ErrorState *const ftperr = new ErrorState(error, httpStatus, fwd->request);
+    ErrorState *ftperr;
+
+    if (err) {
+        debugs(9, 6, "error=" << err->type << ", code=" << xerrno <<
+               ", status=" << err->httpStatus);
+        error = err->type;
+        ftperr = err;
+    } else {
+        Http::StatusCode httpStatus = failedHttpStatus(error);
+        ftperr = new ErrorState(error, httpStatus, fwd->request);
+    }
+
     ftperr->xerrno = xerrno;
 
     ftperr->ftp.server_msg = ctrl.message;
@@ -273,10 +284,11 @@ Ftp::Client::failed(err_type error, int xerrno)
     if (reply)
         ftperr->ftp.reply = xstrdup(reply);
 
-    fwd->request->detailError(error, xerrno);
-    fwd->fail(ftperr);
-
-    closeServer(); // we failed, so no serverComplete()
+    if (!err) {
+        fwd->request->detailError(error, xerrno);
+        fwd->fail(ftperr);
+        closeServer(); // we failed, so no serverComplete()
+    }
 }
 
 Http::StatusCode
@@ -302,6 +314,11 @@ Ftp::Client::scheduleReadControlReply(int buffered_ok)
         /* We've already read some reply data */
         handleControlReply();
     } else {
+
+        if (!Comm::IsConnOpen(ctrl.conn)) {
+            debugs(9, 3, "cannot read without ctrl " << ctrl.conn);
+            return;
+        }
         /*
          * Cancel the timeout on the Data socket (if any) and
          * establish one on the control socket.
@@ -331,16 +348,16 @@ Ftp::Client::readControlReply(const CommIoCbParams &io)
     debugs(9, 3, "FD " << io.fd << ", Read " << io.size << " bytes");
 
     if (io.size > 0) {
-        kb_incr(&(statCounter.server.all.kbytes_in), io.size);
-        kb_incr(&(statCounter.server.ftp.kbytes_in), io.size);
+        statCounter.server.all.kbytes_in += io.size;
+        statCounter.server.ftp.kbytes_in += io.size;
     }
 
     if (io.flag == Comm::ERR_CLOSING)
         return;
 
     if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
-        abortTransaction("entry aborted during control reply read");
-        return;
+        if (abortOnData("entry aborted during control reply read"))
+            return;
     }
 
     assert(ctrl.offset < ctrl.size);
@@ -370,7 +387,7 @@ Ftp::Client::readControlReply(const CommIoCbParams &io)
         }
 
         /* XXX this may end up having to be serverComplete() .. */
-        abortTransaction("zero control reply read");
+        abortAll("zero control reply read");
         return;
     }
 
@@ -425,6 +442,11 @@ Ftp::Client::handlePasvReply(Ip::Address &srvAddr)
     char *buf;
     debugs(9, 3, status());
 
+    if (!Comm::IsConnOpen(ctrl.conn)) {
+        debugs(9, 5, "The control connection to the remote end is closed");
+        return false;
+    }
+
     if (code != 227) {
         debugs(9, 2, "PASV not supported by remote end");
         return false;
@@ -456,6 +478,11 @@ Ftp::Client::handleEpsvReply(Ip::Address &remoteAddr)
     char *buf;
     debugs(9, 3, status());
 
+    if (!Comm::IsConnOpen(ctrl.conn)) {
+        debugs(9, 5, "The control connection to the remote end is closed");
+        return false;
+    }
+
     if (code != 229 && code != 522) {
         if (code == 200) {
             /* handle broken servers (RFC 2428 says OK code for EPSV MUST be 229 not 200) */
@@ -509,6 +536,8 @@ Ftp::Client::handleEpsvReply(Ip::Address &remoteAddr)
             debugs(9, DBG_IMPORTANT, "WARNING: Server at " << ctrl.conn->remote << " sent unknown protocol negotiation hint: " << buf);
             return sendPassive();
         }
+        /* coverity[unreachable] */
+        /* safeguard against possible future bugs in above conditions */
         failed(ERR_FTP_FAILURE, 0);
         return false;
     }
@@ -588,9 +617,9 @@ Ftp::Client::sendEprt()
     /* Which can be used by EITHER protocol. */
     debugs(9, 3, "Listening for FTP data connection on port" << comm_local_port(data.conn->fd) << " or port?" << data.conn->local.port());
     mb.appendf("EPRT |%d|%s|%d|%s",
-              ( data.conn->local.isIPv6() ? 2 : 1 ),
-              data.conn->local.toStr(buf,MAX_IPSTRLEN),
-              comm_local_port(data.conn->fd), Ftp::crlf );
+               ( data.conn->local.isIPv6() ? 2 : 1 ),
+               data.conn->local.toStr(buf,MAX_IPSTRLEN),
+               comm_local_port(data.conn->fd), Ftp::crlf );
 
     state = SENT_EPRT;
     writeCommand(mb.content());
@@ -716,6 +745,11 @@ Ftp::Client::sendPassive()
 void
 Ftp::Client::connectDataChannel()
 {
+    if (!Comm::IsConnOpen(ctrl.conn)) {
+        debugs(9, 5, "The control connection to the remote end is closed");
+        return;
+    }
+
     safe_free(ctrl.last_command);
 
     safe_free(ctrl.last_reply);
@@ -806,8 +840,8 @@ Ftp::Client::writeCommandCallback(const CommIoCbParams &io)
 
     if (io.size > 0) {
         fd_bytes(io.fd, io.size, FD_WRITE);
-        kb_incr(&(statCounter.server.all.kbytes_out), io.size);
-        kb_incr(&(statCounter.server.ftp.kbytes_out), io.size);
+        statCounter.server.all.kbytes_out += io.size;
+        statCounter.server.ftp.kbytes_out += io.size;
     }
 
     if (io.flag == Comm::ERR_CLOSING)
@@ -827,6 +861,7 @@ Ftp::Client::ctrlClosed(const CommCloseCbParams &)
 {
     debugs(9, 4, status());
     ctrl.clear();
+    doneWithFwd = "ctrlClosed()"; // assume FwdState is monitoring too
     mustStop("Ftp::Client::ctrlClosed");
 }
 
@@ -892,8 +927,8 @@ Ftp::Client::dataRead(const CommIoCbParams &io)
     debugs(9, 3, "FD " << io.fd << " Read " << io.size << " bytes");
 
     if (io.size > 0) {
-        kb_incr(&(statCounter.server.all.kbytes_in), io.size);
-        kb_incr(&(statCounter.server.ftp.kbytes_in), io.size);
+        statCounter.server.all.kbytes_in += io.size;
+        statCounter.server.ftp.kbytes_in += io.size;
     }
 
     if (io.flag == Comm::ERR_CLOSING)
@@ -902,7 +937,7 @@ Ftp::Client::dataRead(const CommIoCbParams &io)
     assert(io.fd == data.conn->fd);
 
     if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
-        abortTransaction("entry aborted during dataRead");
+        abortOnData("entry aborted during dataRead");
         return;
     }
 
@@ -979,24 +1014,12 @@ Ftp::Client::dataComplete()
     scheduleReadControlReply(1);
 }
 
-/**
- * Quickly abort the transaction
- *
- \todo destruction should be sufficient as the destructor should cleanup,
- * including canceling close handlers
- */
 void
-Ftp::Client::abortTransaction(const char *reason)
+Ftp::Client::abortAll(const char *reason)
 {
     debugs(9, 3, "aborting transaction for " << reason <<
            "; FD " << (ctrl.conn!=NULL?ctrl.conn->fd:-1) << ", Data FD " << (data.conn!=NULL?data.conn->fd:-1) << ", this " << this);
-    if (Comm::IsConnOpen(ctrl.conn)) {
-        ctrl.conn->close();
-        return;
-    }
-
-    fwd->handleUnregisteredServerEnd();
-    mustStop("Ftp::Client::abortTransaction");
+    mustStop(reason);
 }
 
 /**
@@ -1018,7 +1041,7 @@ void
 Ftp::Client::sentRequestBody(const CommIoCbParams &io)
 {
     if (io.size > 0)
-        kb_incr(&(statCounter.server.ftp.kbytes_out), io.size);
+        statCounter.server.ftp.kbytes_out += io.size;
     ::Client::sentRequestBody(io);
 }