FtpRelay.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9/* DEBUG: section 09 File Transfer Protocol (FTP) */
10
11#include "squid.h"
12#include "anyp/PortCfg.h"
14#include "client_side.h"
15#include "clients/forward.h"
16#include "clients/FtpClient.h"
18#include "ftp/Elements.h"
19#include "ftp/Parsing.h"
20#include "http/Stream.h"
21#include "HttpHdrCc.h"
22#include "HttpRequest.h"
23#include "sbuf/SBuf.h"
24#include "servers/FtpServer.h"
25#include "Store.h"
26#include "wordlist.h"
27
28namespace Ftp
29{
30
34class Relay: public Ftp::Client
35{
37
38public:
39 explicit Relay(FwdState *const fwdState);
40 ~Relay() override;
41
42protected:
43 const Ftp::MasterState &master() const;
46 void serverState(const Ftp::ServerState newState);
47
48 /* Ftp::Client API */
49 void failed(err_type error = ERR_NONE, int xerrno = 0, ErrorState *ftperr = nullptr) override;
50 void dataChannelConnected(const CommConnectCbParams &io) override;
51
52 /* Client API */
53 virtual void serverComplete();
54 void handleControlReply() override;
55 void processReplyBody() override;
57 bool mayReadVirginReplyBody() const override;
58 void completeForwarding() override;
59 bool abortOnData(const char *reason) override;
60
61 /* AsyncJob API */
62 void start() override;
63 void swanSong() override;
64
65 void forwardReply();
66 void forwardError(err_type error = ERR_NONE, int xerrno = 0);
67 void failedErrorMessage(err_type error, int xerrno);
68 HttpReply *createHttpReply(const Http::StatusCode httpStatus, const int64_t clen = 0);
69 void handleDataRequest();
70 void startDataDownload();
71 void startDataUpload();
72 bool startDirTracking();
73 void stopDirTracking();
74 bool weAreTrackingDir() const {return savedReply.message != nullptr;}
75
76 typedef void (Relay::*PreliminaryCb)();
80
81 typedef void (Relay::*SM_FUNC)();
82 static const SM_FUNC SM_FUNCS[];
83 void readGreeting();
84 void sendCommand();
85 void readReply();
86 void readFeatReply();
87 void readPasvReply();
88 void readDataReply();
90 void readEpsvReply();
91 void readCwdOrCdupReply();
93
95
97 void stopOriginWait(int code);
99 static void HandleStoreAbort(Relay *);
100
102
106
107 struct {
110 char *lastReply;
113};
114
115} // namespace Ftp
116
118
120 &Ftp::Relay::readGreeting, // BEGIN
123 nullptr,/* &Ftp::Relay::readReply */ // SENT_TYPE
124 nullptr,/* &Ftp::Relay::readReply */ // SENT_MDTM
125 nullptr,/* &Ftp::Relay::readReply */ // SENT_SIZE
126 nullptr, // SENT_EPRT
127 nullptr, // SENT_PORT
128 &Ftp::Relay::readEpsvReply, // SENT_EPSV_ALL
129 &Ftp::Relay::readEpsvReply, // SENT_EPSV_1
130 &Ftp::Relay::readEpsvReply, // SENT_EPSV_2
131 &Ftp::Relay::readPasvReply, // SENT_PASV
133 nullptr,/* &Ftp::Relay::readDataReply, */ // SENT_LIST
134 nullptr,/* &Ftp::Relay::readDataReply, */ // SENT_NLST
135 nullptr,/* &Ftp::Relay::readReply */ // SENT_REST
136 nullptr,/* &Ftp::Relay::readDataReply */ // SENT_RETR
137 nullptr,/* &Ftp::Relay::readReply */ // SENT_STOR
138 nullptr,/* &Ftp::Relay::readReply */ // SENT_QUIT
139 &Ftp::Relay::readTransferDoneReply, // READING_DATA
140 &Ftp::Relay::readReply, // WRITING_DATA
141 nullptr,/* &Ftp::Relay::readReply */ // SENT_MKDIR
142 &Ftp::Relay::readFeatReply, // SENT_FEAT
143 nullptr,/* &Ftp::Relay::readPwdReply */ // SENT_PWD
144 &Ftp::Relay::readCwdOrCdupReply, // SENT_CDUP
145 &Ftp::Relay::readDataReply,// SENT_DATA_REQUEST
146 &Ftp::Relay::readReply, // SENT_COMMAND
147 nullptr
148};
149
151 AsyncJob("Ftp::Relay"),
152 Ftp::Client(fwdState),
153 thePreliminaryCb(nullptr),
154 forwardingCompleted(false),
155 originWaitInProgress(false)
156{
157 savedReply.message = nullptr;
158 savedReply.lastCommand = nullptr;
159 savedReply.lastReply = nullptr;
160 savedReply.replyCode = 0;
161
162 // Prevent the future response from becoming public and being shared/cached
163 // because FTP does not support response cachability and freshness checks.
165 AsyncCall::Pointer call = asyncCall(9, 4, "Ftp::Relay::Abort", cbdataDialer(&Relay::HandleStoreAbort, this));
167}
168
170{
171 entry->unregisterAbortCallback("Ftp::Relay object destructed");
172 // Client, our parent, calls entry->unlock().
173 // Client does not currently un/registerAbortCallback() because
174 // FwdState does that for other Client kids; \see FwdState::start().
175
176 closeServer(); // TODO: move to clients/Client.cc?
177 if (savedReply.message)
178 wordlistDestroy(&savedReply.message);
179
180 xfree(savedReply.lastCommand);
181 xfree(savedReply.lastReply);
182}
183
184void
186{
187 if (!master().clientReadGreeting)
189 else if (serverState() == fssHandleDataRequest ||
190 serverState() == fssHandleUploadRequest)
191 handleDataRequest();
192 else
193 sendCommand();
194}
195
196void
198{
199 stopOriginWait(0);
201}
202
205void
207{
208 stopOriginWait(ctrl.replycode);
209
210 CbcPointer<ConnStateData> &mgr = fwd->request->clientConnectionManager;
211 if (mgr.valid()) {
212 if (Comm::IsConnOpen(ctrl.conn)) {
213 debugs(9, 7, "completing FTP server " << ctrl.conn <<
214 " after " << ctrl.replycode);
215 fwd->unregister(ctrl.conn);
216 if (ctrl.replycode == 221) { // Server sends FTP 221 before closing
217 mgr->unpinConnection(false);
218 ctrl.close();
219 } else {
220 CallJobHere1(9, 4, mgr,
222 notePinnedConnectionBecameIdle,
223 ConnStateData::PinnedIdleContext(ctrl.conn, fwd->request));
224 ctrl.forget();
225 }
226 }
227 }
229}
230
235{
236 CbcPointer<ConnStateData> &mgr = fwd->request->clientConnectionManager;
237 if (mgr.valid()) {
238 if (Ftp::Server *srv = dynamic_cast<Ftp::Server*>(mgr.get()))
239 return *srv->master;
240 }
241 // this code will not be necessary once the master is inside MasterXaction
242 debugs(9, 3, "our server side is gone: " << mgr);
243 static Ftp::MasterState Master;
244 Master = Ftp::MasterState();
245 return Master;
246}
247
249const Ftp::MasterState &
251{
252 return const_cast<Ftp::Relay*>(this)->updateMaster(); // avoid code dupe
253}
254
256void
258{
259 Ftp::ServerState &cltState = updateMaster().serverState;
260 debugs(9, 3, "client state was " << cltState << " now: " << newState);
261 cltState = newState;
262}
263
272void
274{
275 debugs(9, 5, forwardingCompleted);
276 if (forwardingCompleted)
277 return;
278 forwardingCompleted = true;
280}
281
282void
284{
285 if (!doneWithServer())
286 serverState(fssError);
287
288 // TODO: we need to customize ErrorState instead
289 if (entry->isEmpty())
290 failedErrorMessage(error, xerrno); // as a reply
291
292 Ftp::Client::failed(error, xerrno, ftpErr);
293}
294
295void
297{
298 const Http::StatusCode httpStatus = failedHttpStatus(error);
299 HttpReply *const reply = createHttpReply(httpStatus);
300 entry->replaceHttpReply(reply);
301 fwd->request->detailError(error, SysErrorDetail::NewIfAny(xerrno));
302}
303
304void
306{
307 debugs(9, 3, status());
308
309 if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
310 /*
311 * probably was aborted because content length exceeds one
312 * of the maximum size limits.
313 */
314 abortOnData("entry aborted after calling appendSuccessHeader()");
315 return;
316 }
317
318 if (master().userDataDone) {
319 // Squid-to-client data transfer done. Abort data transfer on our
320 // side to allow new commands from ftp client
321 abortOnData("Squid-to-client data connection is closed");
322 return;
323 }
324
325#if USE_ADAPTATION
326
327 if (adaptationAccessCheckPending) {
328 debugs(9, 3, "returning due to adaptationAccessCheckPending");
329 return;
330 }
331
332#endif
333
334 if (data.readBuf != nullptr && data.readBuf->hasContent()) {
335 const mb_size_t csize = data.readBuf->contentSize();
336 debugs(9, 5, "writing " << csize << " bytes to the reply");
337 addVirginReplyBody(data.readBuf->content(), csize);
338 data.readBuf->consume(csize);
339 }
340
341 entry->flush();
342
343 maybeReadVirginBody();
344}
345
346void
348{
349 if (!request->clientConnectionManager.valid()) {
350 debugs(9, 5, "client connection gone");
351 closeServer();
352 return;
353 }
354
356 if (ctrl.message == nullptr)
357 return; // didn't get complete reply yet
358
359 assert(state < END);
360 assert(this->SM_FUNCS[state] != nullptr);
361 (this->*SM_FUNCS[state])();
362}
363
364void
366{
368
369 failed(ERR_READ_ERROR);
370}
371
372bool
374{
375 // TODO: move this method to the regular FTP server?
376 return Comm::IsConnOpen(data.conn);
377}
378
379void
381{
382 assert(entry->isEmpty());
383
384 HttpReply *const reply = createHttpReply(Http::scNoContent);
386
387 setVirginReply(reply);
388 markParsedVirginReplyAsWhole("Ftp::Relay::handleControlReply() does not forward partial replies");
389 adaptOrFinalizeReply();
390
391 serverComplete();
392}
393
394void
396{
397 debugs(9, 5, "forwarding preliminary reply to client");
398
399 // we must prevent concurrent ConnStateData::sendControlMsg() calls
400 Must(thePreliminaryCb == nullptr);
401 thePreliminaryCb = cb;
402
403 const HttpReply::Pointer reply = createHttpReply(Http::scContinue);
404
405 // the Sink will use this to call us back after writing 1xx to the client
406 typedef NullaryMemFunT<Relay> CbDialer;
407 const AsyncCall::Pointer call = JobCallback(11, 3, CbDialer, this,
409
410 CallJobHere1(9, 4, request->clientConnectionManager, ConnStateData,
412}
413
414void
416{
417 debugs(9, 5, "proceeding after preliminary reply to client");
418
419 Must(thePreliminaryCb != nullptr);
420 const PreliminaryCb cb = thePreliminaryCb;
421 thePreliminaryCb = nullptr;
422 (this->*cb)();
423}
424
425void
427{
428 failed(error, xerrno);
429}
430
431HttpReply *
432Ftp::Relay::createHttpReply(const Http::StatusCode httpStatus, const int64_t clen)
433{
434 HttpReply *const reply = Ftp::HttpReplyWrapper(ctrl.replycode, ctrl.last_reply, httpStatus, clen);
435 if (ctrl.message) {
436 for (wordlist *W = ctrl.message; W && W->next; W = W->next)
438 // no hdrCacheInit() is needed for after Http::HdrType::FTP_PRE addition
439 }
440 return reply;
441}
442
443void
445{
446 data.addr(master().clientDataAddr);
447 connectDataChannel();
448}
449
450void
452{
453 assert(Comm::IsConnOpen(data.conn));
454
455 debugs(9, 3, "begin data transfer from " << data.conn->remote <<
456 " (" << data.conn->local << ")");
457
458 HttpReply *const reply = createHttpReply(Http::scOkay, -1);
460
461 setVirginReply(reply);
462 adaptOrFinalizeReply();
463
464 maybeReadVirginBody();
465 state = READING_DATA;
466}
467
468void
470{
471 assert(Comm::IsConnOpen(data.conn));
472
473 debugs(9, 3, "begin data transfer to " << data.conn->remote <<
474 " (" << data.conn->local << ")");
475
476 if (!startRequestBodyFlow()) { // register to receive body data
477 failed();
478 return;
479 }
480
481 state = WRITING_DATA;
482}
483
484void
486{
487 assert(!master().clientReadGreeting);
488
489 switch (ctrl.replycode) {
490 case 220:
491 updateMaster().clientReadGreeting = true;
492 if (serverState() == fssBegin)
493 serverState(fssConnected);
494
495 // Do not forward server greeting to the user because our FTP Server
496 // has greeted the user already. Also, an original origin greeting may
497 // confuse a user that has changed the origin mid-air.
498
499 start();
500 break;
501 case 120:
502 if (nullptr != ctrl.message)
503 debugs(9, DBG_IMPORTANT, "FTP server is busy: " << ctrl.message->key);
504 forwardPreliminaryReply(&Ftp::Relay::scheduleReadControlReply);
505 break;
506 default:
507 failed();
508 break;
509 }
510}
511
512void
514{
515 if (!fwd->request->header.has(Http::HdrType::FTP_COMMAND)) {
516 abortAll("Internal error: FTP relay request with no command");
517 return;
518 }
519
520 HttpHeader &header = fwd->request->header;
522 const String &cmd = header.findEntry(Http::HdrType::FTP_COMMAND)->value;
524 const String &params = header.findEntry(Http::HdrType::FTP_ARGUMENTS)->value;
525
526 if (params.size() > 0)
527 debugs(9, 5, "command: " << cmd << ", parameters: " << params);
528 else
529 debugs(9, 5, "command: " << cmd << ", no parameters");
530
531 if (serverState() == fssHandlePasv ||
532 serverState() == fssHandleEpsv ||
533 serverState() == fssHandleEprt ||
534 serverState() == fssHandlePort) {
535 sendPassive();
536 return;
537 }
538
539 SBuf buf;
540 if (params.size() > 0)
541 buf.Printf("%s %s%s", cmd.termedBuf(), params.termedBuf(), Ftp::crlf);
542 else
543 buf.Printf("%s%s", cmd.termedBuf(), Ftp::crlf);
544
545 writeCommand(buf.c_str());
546
547 state =
548 serverState() == fssHandleCdup ? SENT_CDUP :
549 serverState() == fssHandleCwd ? SENT_CWD :
550 serverState() == fssHandleFeat ? SENT_FEAT :
551 serverState() == fssHandleDataRequest ? SENT_DATA_REQUEST :
552 serverState() == fssHandleUploadRequest ? SENT_DATA_REQUEST :
553 serverState() == fssConnected ? SENT_USER :
554 serverState() == fssHandlePass ? SENT_PASS :
555 SENT_COMMAND;
556
557 if (state == SENT_DATA_REQUEST) {
558 CbcPointer<ConnStateData> &mgr = fwd->request->clientConnectionManager;
559 if (mgr.valid()) {
560 if (Ftp::Server *srv = dynamic_cast<Ftp::Server*>(mgr.get())) {
561 typedef NullaryMemFunT<Ftp::Server> CbDialer;
562 AsyncCall::Pointer call = JobCallback(11, 3, CbDialer, srv,
564 ScheduleCallHere(call);
565 originWaitInProgress = true;
566 }
567 }
568 }
569}
570
571void
573{
574 assert(serverState() == fssConnected ||
575 serverState() == fssHandleUploadRequest);
576
577 if (Is1xx(ctrl.replycode))
578 forwardPreliminaryReply(&Ftp::Relay::scheduleReadControlReply);
579 else
580 forwardReply();
581}
582
583void
585{
586 assert(serverState() == fssHandleFeat);
587
588 if (Is1xx(ctrl.replycode))
589 return; // ignore preliminary replies
590
591 forwardReply();
592}
593
594void
596{
597 assert(serverState() == fssHandlePasv || serverState() == fssHandleEpsv || serverState() == fssHandlePort || serverState() == fssHandleEprt);
598
599 if (Is1xx(ctrl.replycode))
600 return; // ignore preliminary replies
601
602 if (handlePasvReply(updateMaster().clientDataAddr))
603 forwardReply();
604 else
605 forwardError();
606}
607
608void
610{
611 if (Is1xx(ctrl.replycode))
612 return; // ignore preliminary replies
613
614 if (handleEpsvReply(updateMaster().clientDataAddr)) {
615 if (ctrl.message == nullptr)
616 return; // didn't get complete reply yet
617
618 forwardReply();
619 } else
620 forwardError();
621}
622
623void
625{
626 assert(serverState() == fssHandleDataRequest ||
627 serverState() == fssHandleUploadRequest);
628
629 if (ctrl.replycode == 125 || ctrl.replycode == 150) {
630 if (serverState() == fssHandleDataRequest)
631 forwardPreliminaryReply(&Ftp::Relay::startDataDownload);
632 else if (fwd->request->forcedBodyContinuation /*&& serverState() == fssHandleUploadRequest*/)
633 startDataUpload();
634 else // serverState() == fssHandleUploadRequest
635 forwardPreliminaryReply(&Ftp::Relay::startDataUpload);
636 } else
637 forwardReply();
638}
639
640bool
642{
643 if (!fwd->request->clientConnectionManager->port->ftp_track_dirs)
644 return false;
645
646 debugs(9, 5, "start directory tracking");
647 savedReply.message = ctrl.message;
648 savedReply.lastCommand = ctrl.last_command;
649 savedReply.lastReply = ctrl.last_reply;
650 savedReply.replyCode = ctrl.replycode;
651
652 ctrl.last_command = nullptr;
653 ctrl.last_reply = nullptr;
654 ctrl.message = nullptr;
655 ctrl.offset = 0;
656 writeCommand("PWD\r\n");
657 return true;
658}
659
660void
662{
663 debugs(9, 5, "got code from pwd: " << ctrl.replycode << ", msg: " << ctrl.last_reply);
664
665 if (ctrl.replycode == 257)
666 updateMaster().workingDir = Ftp::UnescapeDoubleQuoted(ctrl.last_reply);
667
668 wordlistDestroy(&ctrl.message);
669 safe_free(ctrl.last_command);
670 safe_free(ctrl.last_reply);
671
672 ctrl.message = savedReply.message;
673 ctrl.last_command = savedReply.lastCommand;
674 ctrl.last_reply = savedReply.lastReply;
675 ctrl.replycode = savedReply.replyCode;
676
677 savedReply.message = nullptr;
678 savedReply.lastReply = nullptr;
679 savedReply.lastCommand = nullptr;
680}
681
682void
684{
685 assert(serverState() == fssHandleCwd ||
686 serverState() == fssHandleCdup);
687
688 debugs(9, 5, "got code " << ctrl.replycode << ", msg: " << ctrl.last_reply);
689
690 if (Is1xx(ctrl.replycode))
691 return;
692
693 if (weAreTrackingDir()) { // we are tracking
694 stopDirTracking(); // and forward the delayed response below
695 } else if (startDirTracking())
696 return;
697
698 forwardReply();
699}
700
701void
703{
704 if (Is1xx(ctrl.replycode))
705 return; //Just ignore
706
707 if (weAreTrackingDir()) { // we are tracking
708 stopDirTracking(); // and forward the delayed response below
709 } else if (ctrl.replycode == 230) { // successful login
710 if (startDirTracking())
711 return;
712 }
713
714 forwardReply();
715}
716
717void
719{
720 debugs(9, 3, status());
721
722 // RFC 959 says that code 226 may indicate a successful response to a file
723 // transfer and file abort commands, but since we do not send abort
724 // commands, let's assume it was a successful file transfer.
725 if (ctrl.replycode == 226 || ctrl.replycode == 250) {
726 markParsedVirginReplyAsWhole("Ftp::Relay::readTransferDoneReply() code 226 or 250");
727 } else {
728 debugs(9, DBG_IMPORTANT, "got FTP code " << ctrl.replycode <<
729 " after reading response data");
730 }
731
732 debugs(9, 2, "Complete data downloading");
733
734 serverComplete();
735}
736
737void
739{
740 debugs(9, 3, status());
741 dataConnWait.finish();
742
743 if (io.flag != Comm::OK) {
744 debugs(9, 2, "failed to connect FTP server data channel");
745 forwardError(ERR_CONNECT_FAIL, io.xerrno);
746 return;
747 }
748
749 debugs(9, 2, "connected FTP server data channel: " << io.conn);
750
751 data.opened(io.conn, dataCloser());
752
753 sendCommand();
754}
755
756void
758{
760}
761
762bool
763Ftp::Relay::abortOnData(const char *reason)
764{
765 debugs(9, 3, "aborting transaction for " << reason <<
766 "; FD " << (ctrl.conn != nullptr ? ctrl.conn->fd : -1) << ", Data FD " << (data.conn != nullptr ? data.conn->fd : -1) << ", this " << this);
767 // this method is only called to handle data connection problems
768 // the control connection should keep going
769
770#if USE_ADAPTATION
771 if (adaptedBodySource != nullptr)
772 stopConsumingFrom(adaptedBodySource);
773#endif
774
775 if (Comm::IsConnOpen(data.conn))
776 dataComplete();
777
778 return !Comm::IsConnOpen(ctrl.conn);
779}
780
781void
783{
784 if (originWaitInProgress) {
785 CbcPointer<ConnStateData> &mgr = fwd->request->clientConnectionManager;
786 if (mgr.valid()) {
787 if (Ftp::Server *srv = dynamic_cast<Ftp::Server*>(mgr.get())) {
788 typedef UnaryMemFunT<Ftp::Server, int> CbDialer;
789 AsyncCall::Pointer call = asyncCall(11, 3, "Ftp::Server::stopWaitingForOrigin",
790 CbDialer(srv, &Ftp::Server::stopWaitingForOrigin, code));
791 ScheduleCallHere(call);
792 }
793 }
794 originWaitInProgress = false;
795 }
796}
797
798void
800{
801 debugs(9, 2, "Client Data connection closed!");
802 if (Comm::IsConnOpen(ftpClient->data.conn))
803 ftpClient->dataComplete();
804}
805
806void
807Ftp::StartRelay(FwdState *const fwdState)
808{
809 AsyncJob::Start(new Ftp::Relay(fwdState));
810}
811
#define ScheduleCallHere(call)
Definition: AsyncCall.h:166
RefCount< AsyncCallT< Dialer > > asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
Definition: AsyncCall.h:156
UnaryCbdataDialer< Argument1 > cbdataDialer(typename UnaryCbdataDialer< Argument1 >::Handler *handler, Argument1 *arg1)
#define JobCallback(dbgSection, dbgLevel, Dialer, job, method)
Convenience macro to create a Dialer-based job callback.
Definition: AsyncJobCalls.h:69
#define CallJobHere1(debugSection, debugLevel, job, Class, method, arg1)
Definition: AsyncJobCalls.h:63
CBDATA_NAMESPACED_CLASS_INIT(Ftp, Relay)
SBuf httpHeaderQuoteString(const char *raw)
quotes string using RFC 7230 quoted-string rules
ssize_t mb_size_t
Definition: MemBuf.h:17
#define Must(condition)
Definition: TextException.h:75
void error(char *format,...)
#define assert(EX)
Definition: assert.h:17
static void Start(const Pointer &job)
Definition: AsyncJob.cc:37
Cbc * valid() const
was set and is valid
Definition: CbcPointer.h:41
Cbc * get() const
a temporary valid raw Cbc pointer or NULL
Definition: CbcPointer.h:159
virtual void completeForwarding()
Definition: Client.cc:230
void serverComplete()
Definition: Client.cc:180
virtual void handleRequestBodyProducerAborted()=0
Definition: Client.cc:351
StoreEntry * entry
Definition: Client.h:176
void swanSong() override
Definition: Client.cc:68
int xerrno
The last errno to occur. non-zero if flag is Comm::COMM_ERROR.
Definition: CommCalls.h:83
Comm::Flag flag
comm layer result status.
Definition: CommCalls.h:82
Comm::ConnectionPointer conn
Definition: CommCalls.h:80
parameters for the async notePinnedConnectionBecameIdle() call
Definition: client_side.h:183
void sendControlMsg(HttpControlMsg) override
called to send the 1xx message and notify the Source
void unpinConnection(const bool andClose)
Undo pinConnection() and, optionally, close the pinned connection.
Comm::ConnectionPointer conn
channel descriptor
Definition: FtpClient.h:58
FTP client functionality shared among FTP Gateway and Relay clients.
Definition: FtpClient.h:111
void start() override
called by AsyncStart; do not call directly
Definition: FtpClient.cc:215
virtual void handleControlReply()
Definition: FtpClient.cc:419
void dataComplete()
Definition: FtpClient.cc:1024
void scheduleReadControlReply(int buffered_ok)
Definition: FtpClient.cc:325
DataChannel data
FTP data channel state.
Definition: FtpClient.h:143
virtual void failed(err_type error=ERR_NONE, int xerrno=0, ErrorState *ftperr=nullptr)
handle a fatal transaction error, closing the control connection
Definition: FtpClient.cc:262
Transaction information shared among our FTP client and server jobs.
Definition: FtpServer.h:43
ServerState serverState
what our FTP server is doing
Definition: FtpServer.h:51
bool originWaitInProgress
Definition: FtpRelay.cc:105
void startDataUpload()
Definition: FtpRelay.cc:469
void sendCommand()
Definition: FtpRelay.cc:513
void swanSong() override
Definition: FtpRelay.cc:197
void completeForwarding() override
Definition: FtpRelay.cc:273
virtual void serverComplete()
Definition: FtpRelay.cc:206
void readTransferDoneReply()
Definition: FtpRelay.cc:718
Ftp::MasterState & updateMaster()
Definition: FtpRelay.cc:234
void failedErrorMessage(err_type error, int xerrno)
Definition: FtpRelay.cc:296
void proceedAfterPreliminaryReply()
Definition: FtpRelay.cc:415
void stopDirTracking()
Definition: FtpRelay.cc:661
void forwardReply()
Definition: FtpRelay.cc:380
Ftp::ServerState serverState() const
Definition: FtpRelay.cc:45
void start() override
called by AsyncStart; do not call directly
Definition: FtpRelay.cc:185
void failed(err_type error=ERR_NONE, int xerrno=0, ErrorState *ftperr=nullptr) override
handle a fatal transaction error, closing the control connection
Definition: FtpRelay.cc:283
void(Relay::* PreliminaryCb)()
Definition: FtpRelay.cc:76
const Ftp::MasterState & master() const
A const variant of updateMaster().
Definition: FtpRelay.cc:250
int replyCode
the reply status
Definition: FtpRelay.cc:111
void readReply()
Definition: FtpRelay.cc:572
void readGreeting()
Definition: FtpRelay.cc:485
char * lastCommand
the command caused the reply
Definition: FtpRelay.cc:109
HttpReply * createHttpReply(const Http::StatusCode httpStatus, const int64_t clen=0)
Definition: FtpRelay.cc:432
CBDATA_CHILD(Relay)
struct Ftp::Relay::@39 savedReply
set and delayed while we are tracking using PWD
bool weAreTrackingDir() const
Definition: FtpRelay.cc:74
void readPasvReply()
Definition: FtpRelay.cc:595
bool abortOnData(const char *reason) override
Definition: FtpRelay.cc:763
void forwardError(err_type error=ERR_NONE, int xerrno=0)
Definition: FtpRelay.cc:426
void handleDataRequest()
Definition: FtpRelay.cc:444
Relay(FwdState *const fwdState)
Definition: FtpRelay.cc:150
void stopOriginWait(int code)
Inform Ftp::Server that we are done if originWaitInProgress.
Definition: FtpRelay.cc:782
bool forwardingCompleted
completeForwarding() has been called
Definition: FtpRelay.cc:101
void readFeatReply()
Definition: FtpRelay.cc:584
bool mayReadVirginReplyBody() const override
whether we may receive more virgin response body bytes
Definition: FtpRelay.cc:373
void(Relay::* SM_FUNC)()
Definition: FtpRelay.cc:81
void processReplyBody() override
Definition: FtpRelay.cc:305
void dataChannelConnected(const CommConnectCbParams &io) override
Definition: FtpRelay.cc:738
char * lastReply
last line of reply: reply status plus message
Definition: FtpRelay.cc:110
void readDataReply()
Definition: FtpRelay.cc:624
static void HandleStoreAbort(Relay *)
called by Store if the entry is no longer usable
Definition: FtpRelay.cc:799
bool startDirTracking()
Definition: FtpRelay.cc:641
PreliminaryCb thePreliminaryCb
Definition: FtpRelay.cc:79
void readUserOrPassReply()
Definition: FtpRelay.cc:702
static const SM_FUNC SM_FUNCS[]
Definition: FtpRelay.cc:82
void handleControlReply() override
Definition: FtpRelay.cc:347
~Relay() override
Definition: FtpRelay.cc:169
void startDataDownload()
Definition: FtpRelay.cc:451
void readCwdOrCdupReply()
Definition: FtpRelay.cc:683
void scheduleReadControlReply()
Definition: FtpRelay.cc:757
void readEpsvReply()
Definition: FtpRelay.cc:609
void forwardPreliminaryReply(const PreliminaryCb cb)
Definition: FtpRelay.cc:395
wordlist * message
reply message, one wordlist entry per message line
Definition: FtpRelay.cc:108
void handleRequestBodyProducerAborted() override
Definition: FtpRelay.cc:365
Manages a control connection from an FTP client.
Definition: FtpServer.h:59
void startWaitingForOrigin()
Definition: FtpServer.cc:1761
void stopWaitingForOrigin(int status)
Definition: FtpServer.cc:1771
bundles HTTP 1xx reply and the "successfully forwarded" callback
void putStr(Http::HdrType id, const char *str)
Definition: HttpHeader.cc:996
int has(Http::HdrType id) const
Definition: HttpHeader.cc:938
HttpHeaderEntry * findEntry(Http::HdrType id) const
Definition: HttpHeader.cc:603
@ srcFtp
ftp_port or FTP server
Definition: Message.h:40
uint32_t sources
The message sources.
Definition: Message.h:99
HttpHeader header
Definition: Message.h:74
Definition: SBuf.h:94
const char * c_str()
Definition: SBuf.cc:516
SBuf & Printf(const char *fmt,...) PRINTF_FORMAT_ARG2
Definition: SBuf.cc:214
void registerAbortCallback(const AsyncCall::Pointer &)
notify the StoreEntry writer of a 3rd-party initiated StoreEntry abort
Definition: store.cc:1467
void releaseRequest(const bool shareable=false)
Definition: store.cc:444
char const * termedBuf() const
Definition: SquidString.h:92
size_type size() const
Definition: SquidString.h:73
static ErrorDetail::Pointer NewIfAny(const int errorNo)
wordlist * next
Definition: wordlist.h:33
#define DBG_IMPORTANT
Definition: Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:194
#define EBIT_TEST(flag, bit)
Definition: defines.h:69
@ ENTRY_ABORTED
Definition: enums.h:115
err_type
Definition: forward.h:14
@ ERR_CONNECT_FAIL
Definition: forward.h:30
@ ERR_NONE
Definition: forward.h:15
@ ERR_READ_ERROR
Definition: forward.h:28
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:27
@ OK
Definition: Flag.h:16
Definition: forward.h:24
bool Is1xx(const int sc)
whether this is an informational 1xx response status code
Definition: Elements.h:53
const char * UnescapeDoubleQuoted(const char *quotedPath)
parses an FTP-quoted quote-escaped path
Definition: Parsing.cc:90
ServerState
Definition: FtpServer.h:23
@ fssError
Definition: FtpServer.h:36
@ fssHandlePort
Definition: FtpServer.h:28
@ fssHandleCdup
Definition: FtpServer.h:35
@ fssHandleFeat
Definition: FtpServer.h:26
@ fssHandlePasv
Definition: FtpServer.h:27
@ fssConnected
Definition: FtpServer.h:25
@ fssHandleEprt
Definition: FtpServer.h:31
@ fssHandleCwd
Definition: FtpServer.h:33
@ fssHandlePass
Definition: FtpServer.h:34
@ fssHandleUploadRequest
Definition: FtpServer.h:30
@ fssBegin
Definition: FtpServer.h:24
@ fssHandleEpsv
Definition: FtpServer.h:32
@ fssHandleDataRequest
Definition: FtpServer.h:29
const char *const crlf
Definition: FtpClient.cc:40
void StartRelay(FwdState *const fwdState)
A new FTP Relay job.
Definition: FtpRelay.cc:807
HttpReply * HttpReplyWrapper(const int ftpStatus, const char *ftpReason, const Http::StatusCode httpStatus, const int64_t clen)
Create an internal HttpReply structure to house FTP control response info.
Definition: Elements.cc:30
StatusCode
Definition: StatusCode.h:20
@ scOkay
Definition: StatusCode.h:26
@ scContinue
Definition: StatusCode.h:22
@ scNoContent
Definition: StatusCode.h:30
#define xfree
int code
Definition: smb-errors.c:145
void wordlistDestroy(wordlist **list)
destroy a wordlist
Definition: wordlist.cc:16
#define safe_free(x)
Definition: xalloc.h:73

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors