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"
13 #include "base/AsyncCbdataCalls.h"
14 #include "client_side.h"
15 #include "clients/forward.h"
16 #include "clients/FtpClient.h"
17 #include "error/SysErrorDetail.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 
28 namespace Ftp
29 {
30 
34 class Relay: public Ftp::Client
35 {
37 
38 public:
39  explicit Relay(FwdState *const fwdState);
40  ~Relay() override;
41 
42 protected:
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;
56  void handleRequestBodyProducerAborted() 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();
89  void readTransferDoneReply();
90  void readEpsvReply();
91  void readCwdOrCdupReply();
92  void readUserOrPassReply();
93 
95 
97  void stopOriginWait(int code);
99  static void HandleStoreAbort(Relay *);
100 
102 
106 
107  struct {
109  char *lastCommand;
110  char *lastReply;
111  int replyCode;
112  } savedReply;
113 };
114 
115 } // namespace Ftp
116 
118 
120  &Ftp::Relay::readGreeting, // BEGIN
121  &Ftp::Relay::readUserOrPassReply, // SENT_USER
122  &Ftp::Relay::readUserOrPassReply, // SENT_PASS
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
132  &Ftp::Relay::readCwdOrCdupReply, // SENT_CWD
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 
150 Ftp::Relay::Relay(FwdState *const fwdState):
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 
184 void
186 {
187  if (!master().clientReadGreeting)
189  else if (serverState() == fssHandleDataRequest ||
190  serverState() == fssHandleUploadRequest)
191  handleDataRequest();
192  else
193  sendCommand();
194 }
195 
196 void
198 {
199  stopOriginWait(0);
201 }
202 
205 void
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 
249 const Ftp::MasterState &
251 {
252  return const_cast<Ftp::Relay*>(this)->updateMaster(); // avoid code dupe
253 }
254 
256 void
258 {
259  Ftp::ServerState &cltState = updateMaster().serverState;
260  debugs(9, 3, "client state was " << cltState << " now: " << newState);
261  cltState = newState;
262 }
263 
272 void
274 {
275  debugs(9, 5, forwardingCompleted);
276  if (forwardingCompleted)
277  return;
278  forwardingCompleted = true;
280 }
281 
282 void
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 
295 void
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 
304 void
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 
346 void
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 
364 void
366 {
368 
369  failed(ERR_READ_ERROR);
370 }
371 
372 bool
374 {
375  // TODO: move this method to the regular FTP server?
376  return Comm::IsConnOpen(data.conn);
377 }
378 
379 void
381 {
382  assert(entry->isEmpty());
383 
384  HttpReply *const reply = createHttpReply(Http::scNoContent);
385  reply->sources |= Http::Message::srcFtp;
386 
387  setVirginReply(reply);
388  markParsedVirginReplyAsWhole("Ftp::Relay::handleControlReply() does not forward partial replies");
389  adaptOrFinalizeReply();
390 
391  serverComplete();
392 }
393 
394 void
395 Ftp::Relay::forwardPreliminaryReply(const PreliminaryCb cb)
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 
414 void
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 
425 void
427 {
428  failed(error, xerrno);
429 }
430 
431 HttpReply *
432 Ftp::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 
443 void
445 {
446  data.addr(master().clientDataAddr);
447  connectDataChannel();
448 }
449 
450 void
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);
459  reply->sources |= Http::Message::srcFtp;
460 
461  setVirginReply(reply);
462  adaptOrFinalizeReply();
463 
464  maybeReadVirginBody();
465  state = READING_DATA;
466 }
467 
468 void
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 
484 void
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 
512 void
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 
571 void
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 
583 void
585 {
586  assert(serverState() == fssHandleFeat);
587 
588  if (Is1xx(ctrl.replycode))
589  return; // ignore preliminary replies
590 
591  forwardReply();
592 }
593 
594 void
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 
608 void
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 
623 void
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 
640 bool
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 
660 void
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 
682 void
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 
701 void
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 
717 void
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 
737 void
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 
756 void
758 {
760 }
761 
762 bool
763 Ftp::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 
781 void
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 
798 void
800 {
801  debugs(9, 2, "Client Data connection closed!");
802  if (Comm::IsConnOpen(ftpClient->data.conn))
803  ftpClient->dataComplete();
804 }
805 
806 void
807 Ftp::StartRelay(FwdState *const fwdState)
808 {
809  AsyncJob::Start(new Ftp::Relay(fwdState));
810 }
811 
int replyCode
the reply status
Definition: FtpRelay.cc:111
Cbc * get() const
a temporary valid raw Cbc pointer or NULL
Definition: CbcPointer.h:159
@ fssHandleCdup
Definition: FtpServer.h:35
void startDataUpload()
Definition: FtpRelay.cc:469
void readFeatReply()
Definition: FtpRelay.cc:584
StoreEntry * entry
Definition: Client.h:176
void wordlistDestroy(wordlist **list)
destroy a wordlist
Definition: wordlist.cc:16
@ ERR_READ_ERROR
Definition: forward.h:28
bool Is1xx(const int sc)
whether this is an informational 1xx response status code
Definition: Elements.h:53
void releaseRequest(const bool shareable=false)
Definition: store.cc:458
HttpHeader header
Definition: Message.h:74
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
Transaction information shared among our FTP client and server jobs.
Definition: FtpServer.h:42
@ fssHandleUploadRequest
Definition: FtpServer.h:30
const char *const crlf
Definition: FtpClient.cc:40
@ fssBegin
Definition: FtpServer.h:24
#define ScheduleCallHere(call)
Definition: AsyncCall.h:166
virtual void handleRequestBodyProducerAborted()=0
Definition: Client.cc:350
@ ENTRY_ABORTED
Definition: enums.h:110
void error(char *format,...)
Ftp::MasterState & updateMaster()
Definition: FtpRelay.cc:234
@ fssHandleCwd
Definition: FtpServer.h:33
void sendControlMsg(HttpControlMsg) override
called to send the 1xx message and notify the Source
Definition: SBuf.h:93
static const SM_FUNC SM_FUNCS[]
Definition: FtpRelay.cc:82
void sendCommand()
Definition: FtpRelay.cc:513
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
const Ftp::MasterState & master() const
A const variant of updateMaster().
Definition: FtpRelay.cc:250
bool originWaitInProgress
Definition: FtpRelay.cc:105
~Relay() override
Definition: FtpRelay.cc:169
void startDataDownload()
Definition: FtpRelay.cc:451
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:27
@ OK
Definition: Flag.h:16
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
bool forwardingCompleted
completeForwarding() has been called
Definition: FtpRelay.cc:101
@ ERR_NONE
Definition: forward.h:15
StatusCode
Definition: StatusCode.h:20
err_type
Definition: forward.h:14
void processReplyBody() override
Definition: FtpRelay.cc:305
ServerState
Definition: FtpServer.h:23
int xerrno
The last errno to occur. non-zero if flag is Comm::COMM_ERROR.
Definition: CommCalls.h:83
RefCount< AsyncCallT< Dialer > > asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
Definition: AsyncCall.h:156
char * lastCommand
the command caused the reply
Definition: FtpRelay.cc:109
void serverComplete()
Definition: Client.cc:180
FTP client functionality shared among FTP Gateway and Relay clients.
Definition: FtpClient.h:110
Definition: forward.h:23
void scheduleReadControlReply()
Definition: FtpRelay.cc:757
virtual void completeForwarding()
Definition: Client.cc:229
static void HandleStoreAbort(Relay *)
called by Store if the entry is no longer usable
Definition: FtpRelay.cc:799
void stopOriginWait(int code)
Inform Ftp::Server that we are done if originWaitInProgress.
Definition: FtpRelay.cc:782
UnaryCbdataDialer< Argument1 > cbdataDialer(typename UnaryCbdataDialer< Argument1 >::Handler *handler, Argument1 *arg1)
@ fssConnected
Definition: FtpServer.h:25
parameters for the async notePinnedConnectionBecameIdle() call
Definition: client_side.h:182
void readCwdOrCdupReply()
Definition: FtpRelay.cc:683
void start() override
called by AsyncStart; do not call directly
Definition: FtpClient.cc:215
void readDataReply()
Definition: FtpRelay.cc:624
HttpReply * createHttpReply(const Http::StatusCode httpStatus, const int64_t clen=0)
Definition: FtpRelay.cc:432
virtual void handleControlReply()
Definition: FtpClient.cc:419
bundles HTTP 1xx reply and the "successfully forwarded" callback
void dataChannelConnected(const CommConnectCbParams &io) override
Definition: FtpRelay.cc:738
static ErrorDetail::Pointer NewIfAny(const int errorNo)
void readEpsvReply()
Definition: FtpRelay.cc:609
CBDATA_NAMESPACED_CLASS_INIT(Ftp, Relay)
void dataComplete()
Definition: FtpClient.cc:1026
void handleDataRequest()
Definition: FtpRelay.cc:444
bool startDirTracking()
Definition: FtpRelay.cc:641
#define EBIT_TEST(flag, bit)
Definition: defines.h:67
SBuf & Printf(const char *fmt,...) PRINTF_FORMAT_ARG2
Definition: SBuf.cc:214
void swanSong() override
Definition: Client.cc:68
@ fssHandlePort
Definition: FtpServer.h:28
void stopDirTracking()
Definition: FtpRelay.cc:661
void scheduleReadControlReply(int buffered_ok)
Definition: FtpClient.cc:325
Comm::ConnectionPointer conn
Definition: CommCalls.h:80
#define safe_free(x)
Definition: xalloc.h:73
@ srcFtp
ftp_port or FTP server
Definition: Message.h:40
void stopWaitingForOrigin(int status)
Definition: FtpServer.cc:1771
#define assert(EX)
Definition: assert.h:17
void handleControlReply() override
Definition: FtpRelay.cc:347
@ scContinue
Definition: StatusCode.h:22
SBuf httpHeaderQuoteString(const char *raw)
quotes string using RFC 7230 quoted-string rules
char * lastReply
last line of reply: reply status plus message
Definition: FtpRelay.cc:110
const char * UnescapeDoubleQuoted(const char *quotedPath)
parses an FTP-quoted quote-escaped path
Definition: Parsing.cc:90
Comm::Flag flag
comm layer result status.
Definition: CommCalls.h:82
#define JobCallback(dbgSection, dbgLevel, Dialer, job, method)
Convenience macro to create a Dialer-based job callback.
Definition: AsyncJobCalls.h:70
void completeForwarding() override
Definition: FtpRelay.cc:273
@ fssHandlePasv
Definition: FtpServer.h:27
Comm::ConnectionPointer conn
channel descriptor
Definition: FtpClient.h:58
const char * c_str()
Definition: SBuf.cc:516
void readTransferDoneReply()
Definition: FtpRelay.cc:718
void readReply()
Definition: FtpRelay.cc:572
Manages a control connection from an FTP client.
Definition: FtpServer.h:58
void forwardError(err_type error=ERR_NONE, int xerrno=0)
Definition: FtpRelay.cc:426
void start() override
called by AsyncStart; do not call directly
Definition: FtpRelay.cc:185
#define xfree
int code
Definition: smb-errors.c:145
void forwardPreliminaryReply(const PreliminaryCb cb)
Definition: FtpRelay.cc:395
DataChannel data
FTP data channel state.
Definition: FtpClient.h:143
wordlist * next
Definition: wordlist.h:60
Relay(FwdState *const fwdState)
Definition: FtpRelay.cc:150
@ fssHandleEpsv
Definition: FtpServer.h:32
uint32_t sources
The message sources.
Definition: Message.h:99
@ fssHandlePass
Definition: FtpServer.h:34
void readGreeting()
Definition: FtpRelay.cc:485
struct Ftp::Relay::@38 savedReply
set and delayed while we are tracking using PWD
@ fssError
Definition: FtpServer.h:36
void readUserOrPassReply()
Definition: FtpRelay.cc:702
HttpHeaderEntry * findEntry(Http::HdrType id) const
Definition: HttpHeader.cc:602
const char * termedBuf() const
Definition: SquidString.h:92
virtual void serverComplete()
Definition: FtpRelay.cc:206
void StartRelay(FwdState *const fwdState)
A new FTP Relay job.
Definition: FtpRelay.cc:807
@ scNoContent
Definition: StatusCode.h:31
ServerState serverState
what our FTP server is doing
Definition: FtpServer.h:51
int has(Http::HdrType id) const
Definition: HttpHeader.cc:937
void putStr(Http::HdrType id, const char *str)
Definition: HttpHeader.cc:995
size_type size() const
Definition: SquidString.h:73
@ ERR_CONNECT_FAIL
Definition: forward.h:30
Ftp::ServerState serverState() const
Definition: FtpRelay.cc:45
@ fssHandleEprt
Definition: FtpServer.h:31
#define Must(condition)
Definition: TextException.h:75
CBDATA_CHILD(Relay)
void failedErrorMessage(err_type error, int xerrno)
Definition: FtpRelay.cc:296
PreliminaryCb thePreliminaryCb
Definition: FtpRelay.cc:79
#define DBG_IMPORTANT
Definition: Stream.h:38
ssize_t mb_size_t
Definition: MemBuf.h:17
void swanSong() override
Definition: FtpRelay.cc:197
@ fssHandleDataRequest
Definition: FtpServer.h:29
bool weAreTrackingDir() const
Definition: FtpRelay.cc:74
void readPasvReply()
Definition: FtpRelay.cc:595
@ scOkay
Definition: StatusCode.h:27
void registerAbortCallback(const AsyncCall::Pointer &)
notify the StoreEntry writer of a 3rd-party initiated StoreEntry abort
Definition: store.cc:1481
bool mayReadVirginReplyBody() const override
whether we may receive more virgin response body bytes
Definition: FtpRelay.cc:373
void proceedAfterPreliminaryReply()
Definition: FtpRelay.cc:415
void handleRequestBodyProducerAborted() override
Definition: FtpRelay.cc:365
wordlist * message
reply message, one wordlist entry per message line
Definition: FtpRelay.cc:108
void startWaitingForOrigin()
Definition: FtpServer.cc:1761
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
void forwardReply()
Definition: FtpRelay.cc:380
void unpinConnection(const bool andClose)
Undo pinConnection() and, optionally, close the pinned connection.
void(Relay::* PreliminaryCb)()
Definition: FtpRelay.cc:76
bool abortOnData(const char *reason) override
Definition: FtpRelay.cc:763
@ fssHandleFeat
Definition: FtpServer.h:26
void(Relay::* SM_FUNC)()
Definition: FtpRelay.cc:81
static void Start(const Pointer &job)
Definition: AsyncJob.cc:37
#define CallJobHere1(debugSection, debugLevel, job, Class, method, arg1)
Definition: AsyncJobCalls.h:64

 

Introduction

Documentation

Support

Miscellaneous