FTPChannelChild.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "mozilla/net/NeckoChild.h"
  6. #include "mozilla/net/ChannelDiverterChild.h"
  7. #include "mozilla/net/FTPChannelChild.h"
  8. #include "mozilla/dom/TabChild.h"
  9. #include "nsFtpProtocolHandler.h"
  10. #include "nsITabChild.h"
  11. #include "nsStringStream.h"
  12. #include "nsNetUtil.h"
  13. #include "base/compiler_specific.h"
  14. #include "mozilla/ipc/InputStreamUtils.h"
  15. #include "mozilla/ipc/URIUtils.h"
  16. #include "SerializedLoadContext.h"
  17. #include "mozilla/ipc/BackgroundUtils.h"
  18. #include "nsIPrompt.h"
  19. using namespace mozilla::ipc;
  20. #undef LOG
  21. #define LOG(args) MOZ_LOG(gFTPLog, mozilla::LogLevel::Debug, args)
  22. namespace mozilla {
  23. namespace net {
  24. FTPChannelChild::FTPChannelChild(nsIURI* uri)
  25. : mIPCOpen(false)
  26. , mUnknownDecoderInvolved(false)
  27. , mCanceled(false)
  28. , mSuspendCount(0)
  29. , mIsPending(false)
  30. , mLastModifiedTime(0)
  31. , mStartPos(0)
  32. , mDivertingToParent(false)
  33. , mFlushedForDiversion(false)
  34. , mSuspendSent(false)
  35. {
  36. LOG(("Creating FTPChannelChild @%x\n", this));
  37. // grab a reference to the handler to ensure that it doesn't go away.
  38. NS_ADDREF(gFtpHandler);
  39. SetURI(uri);
  40. mEventQ = new ChannelEventQueue(static_cast<nsIFTPChannel*>(this));
  41. // We could support thread retargeting, but as long as we're being driven by
  42. // IPDL on the main thread it doesn't buy us anything.
  43. DisallowThreadRetargeting();
  44. }
  45. FTPChannelChild::~FTPChannelChild()
  46. {
  47. LOG(("Destroying FTPChannelChild @%x\n", this));
  48. gFtpHandler->Release();
  49. }
  50. void
  51. FTPChannelChild::AddIPDLReference()
  52. {
  53. MOZ_ASSERT(!mIPCOpen, "Attempt to retain more than one IPDL reference");
  54. mIPCOpen = true;
  55. AddRef();
  56. }
  57. void
  58. FTPChannelChild::ReleaseIPDLReference()
  59. {
  60. MOZ_ASSERT(mIPCOpen, "Attempt to release nonexistent IPDL reference");
  61. mIPCOpen = false;
  62. Release();
  63. }
  64. //-----------------------------------------------------------------------------
  65. // FTPChannelChild::nsISupports
  66. //-----------------------------------------------------------------------------
  67. NS_IMPL_ISUPPORTS_INHERITED(FTPChannelChild,
  68. nsBaseChannel,
  69. nsIFTPChannel,
  70. nsIUploadChannel,
  71. nsIResumableChannel,
  72. nsIProxiedChannel,
  73. nsIChildChannel,
  74. nsIDivertableChannel)
  75. //-----------------------------------------------------------------------------
  76. NS_IMETHODIMP
  77. FTPChannelChild::GetLastModifiedTime(PRTime* lastModifiedTime)
  78. {
  79. *lastModifiedTime = mLastModifiedTime;
  80. return NS_OK;
  81. }
  82. NS_IMETHODIMP
  83. FTPChannelChild::SetLastModifiedTime(PRTime lastModifiedTime)
  84. {
  85. return NS_ERROR_NOT_AVAILABLE;
  86. }
  87. NS_IMETHODIMP
  88. FTPChannelChild::ResumeAt(uint64_t aStartPos, const nsACString& aEntityID)
  89. {
  90. NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
  91. mStartPos = aStartPos;
  92. mEntityID = aEntityID;
  93. return NS_OK;
  94. }
  95. NS_IMETHODIMP
  96. FTPChannelChild::GetEntityID(nsACString& entityID)
  97. {
  98. entityID = mEntityID;
  99. return NS_OK;
  100. }
  101. NS_IMETHODIMP
  102. FTPChannelChild::GetProxyInfo(nsIProxyInfo** aProxyInfo)
  103. {
  104. DROP_DEAD();
  105. }
  106. NS_IMETHODIMP
  107. FTPChannelChild::SetUploadStream(nsIInputStream* stream,
  108. const nsACString& contentType,
  109. int64_t contentLength)
  110. {
  111. NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
  112. mUploadStream = stream;
  113. // NOTE: contentLength is intentionally ignored here.
  114. return NS_OK;
  115. }
  116. NS_IMETHODIMP
  117. FTPChannelChild::GetUploadStream(nsIInputStream** stream)
  118. {
  119. NS_ENSURE_ARG_POINTER(stream);
  120. *stream = mUploadStream;
  121. NS_IF_ADDREF(*stream);
  122. return NS_OK;
  123. }
  124. NS_IMETHODIMP
  125. FTPChannelChild::AsyncOpen(::nsIStreamListener* listener, nsISupports* aContext)
  126. {
  127. LOG(("FTPChannelChild::AsyncOpen [this=%p]\n", this));
  128. NS_ENSURE_TRUE((gNeckoChild), NS_ERROR_FAILURE);
  129. NS_ENSURE_ARG_POINTER(listener);
  130. NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
  131. NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
  132. // Port checked in parent, but duplicate here so we can return with error
  133. // immediately, as we've done since before e10s.
  134. nsresult rv;
  135. rv = NS_CheckPortSafety(nsBaseChannel::URI()); // Need to disambiguate,
  136. // because in the child ipdl,
  137. // a typedef URI is defined...
  138. if (NS_FAILED(rv))
  139. return rv;
  140. mozilla::dom::TabChild* tabChild = nullptr;
  141. nsCOMPtr<nsITabChild> iTabChild;
  142. NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
  143. NS_GET_IID(nsITabChild),
  144. getter_AddRefs(iTabChild));
  145. GetCallback(iTabChild);
  146. if (iTabChild) {
  147. tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
  148. }
  149. if (MissingRequiredTabChild(tabChild, "ftp")) {
  150. return NS_ERROR_ILLEGAL_VALUE;
  151. }
  152. mListener = listener;
  153. mListenerContext = aContext;
  154. // add ourselves to the load group.
  155. if (mLoadGroup)
  156. mLoadGroup->AddRequest(this, nullptr);
  157. OptionalInputStreamParams uploadStream;
  158. nsTArray<mozilla::ipc::FileDescriptor> fds;
  159. SerializeInputStream(mUploadStream, uploadStream, fds);
  160. MOZ_ASSERT(fds.IsEmpty());
  161. FTPChannelOpenArgs openArgs;
  162. SerializeURI(nsBaseChannel::URI(), openArgs.uri());
  163. openArgs.startPos() = mStartPos;
  164. openArgs.entityID() = mEntityID;
  165. openArgs.uploadStream() = uploadStream;
  166. nsCOMPtr<nsILoadInfo> loadInfo;
  167. GetLoadInfo(getter_AddRefs(loadInfo));
  168. rv = mozilla::ipc::LoadInfoToLoadInfoArgs(loadInfo, &openArgs.loadInfo());
  169. NS_ENSURE_SUCCESS(rv, rv);
  170. gNeckoChild->
  171. SendPFTPChannelConstructor(this, tabChild, IPC::SerializedLoadContext(this),
  172. openArgs);
  173. // The socket transport layer in the chrome process now has a logical ref to
  174. // us until OnStopRequest is called.
  175. AddIPDLReference();
  176. mIsPending = true;
  177. mWasOpened = true;
  178. return rv;
  179. }
  180. NS_IMETHODIMP
  181. FTPChannelChild::IsPending(bool* result)
  182. {
  183. *result = mIsPending;
  184. return NS_OK;
  185. }
  186. nsresult
  187. FTPChannelChild::OpenContentStream(bool async,
  188. nsIInputStream** stream,
  189. nsIChannel** channel)
  190. {
  191. NS_RUNTIMEABORT("FTPChannel*Child* should never have OpenContentStream called!");
  192. return NS_OK;
  193. }
  194. //-----------------------------------------------------------------------------
  195. // FTPChannelChild::PFTPChannelChild
  196. //-----------------------------------------------------------------------------
  197. class FTPStartRequestEvent : public ChannelEvent
  198. {
  199. public:
  200. FTPStartRequestEvent(FTPChannelChild* aChild,
  201. const nsresult& aChannelStatus,
  202. const int64_t& aContentLength,
  203. const nsCString& aContentType,
  204. const PRTime& aLastModified,
  205. const nsCString& aEntityID,
  206. const URIParams& aURI)
  207. : mChild(aChild)
  208. , mChannelStatus(aChannelStatus)
  209. , mContentLength(aContentLength)
  210. , mContentType(aContentType)
  211. , mLastModified(aLastModified)
  212. , mEntityID(aEntityID)
  213. , mURI(aURI)
  214. {
  215. }
  216. void Run()
  217. {
  218. mChild->DoOnStartRequest(mChannelStatus, mContentLength, mContentType,
  219. mLastModified, mEntityID, mURI);
  220. }
  221. private:
  222. FTPChannelChild* mChild;
  223. nsresult mChannelStatus;
  224. int64_t mContentLength;
  225. nsCString mContentType;
  226. PRTime mLastModified;
  227. nsCString mEntityID;
  228. URIParams mURI;
  229. };
  230. bool
  231. FTPChannelChild::RecvOnStartRequest(const nsresult& aChannelStatus,
  232. const int64_t& aContentLength,
  233. const nsCString& aContentType,
  234. const PRTime& aLastModified,
  235. const nsCString& aEntityID,
  236. const URIParams& aURI)
  237. {
  238. // mFlushedForDiversion and mDivertingToParent should NEVER be set at this
  239. // stage, as they are set in the listener's OnStartRequest.
  240. MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
  241. "mFlushedForDiversion should be unset before OnStartRequest!");
  242. MOZ_RELEASE_ASSERT(!mDivertingToParent,
  243. "mDivertingToParent should be unset before OnStartRequest!");
  244. LOG(("FTPChannelChild::RecvOnStartRequest [this=%p]\n", this));
  245. mEventQ->RunOrEnqueue(new FTPStartRequestEvent(this, aChannelStatus,
  246. aContentLength, aContentType,
  247. aLastModified, aEntityID,
  248. aURI));
  249. return true;
  250. }
  251. void
  252. FTPChannelChild::DoOnStartRequest(const nsresult& aChannelStatus,
  253. const int64_t& aContentLength,
  254. const nsCString& aContentType,
  255. const PRTime& aLastModified,
  256. const nsCString& aEntityID,
  257. const URIParams& aURI)
  258. {
  259. LOG(("FTPChannelChild::DoOnStartRequest [this=%p]\n", this));
  260. // mFlushedForDiversion and mDivertingToParent should NEVER be set at this
  261. // stage, as they are set in the listener's OnStartRequest.
  262. MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
  263. "mFlushedForDiversion should be unset before OnStartRequest!");
  264. MOZ_RELEASE_ASSERT(!mDivertingToParent,
  265. "mDivertingToParent should be unset before OnStartRequest!");
  266. if (!mCanceled && NS_SUCCEEDED(mStatus)) {
  267. mStatus = aChannelStatus;
  268. }
  269. mContentLength = aContentLength;
  270. SetContentType(aContentType);
  271. mLastModifiedTime = aLastModified;
  272. mEntityID = aEntityID;
  273. nsCString spec;
  274. nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
  275. nsresult rv = uri->GetSpec(spec);
  276. if (NS_SUCCEEDED(rv)) {
  277. rv = nsBaseChannel::URI()->SetSpec(spec);
  278. if (NS_FAILED(rv)) {
  279. Cancel(rv);
  280. }
  281. } else {
  282. Cancel(rv);
  283. }
  284. AutoEventEnqueuer ensureSerialDispatch(mEventQ);
  285. rv = mListener->OnStartRequest(this, mListenerContext);
  286. if (NS_FAILED(rv))
  287. Cancel(rv);
  288. if (mDivertingToParent) {
  289. mListener = nullptr;
  290. mListenerContext = nullptr;
  291. if (mLoadGroup) {
  292. mLoadGroup->RemoveRequest(this, nullptr, mStatus);
  293. }
  294. }
  295. }
  296. class FTPDataAvailableEvent : public ChannelEvent
  297. {
  298. public:
  299. FTPDataAvailableEvent(FTPChannelChild* aChild,
  300. const nsresult& aChannelStatus,
  301. const nsCString& aData,
  302. const uint64_t& aOffset,
  303. const uint32_t& aCount)
  304. : mChild(aChild)
  305. , mChannelStatus(aChannelStatus)
  306. , mData(aData)
  307. , mOffset(aOffset)
  308. , mCount(aCount)
  309. {
  310. }
  311. void Run()
  312. {
  313. mChild->DoOnDataAvailable(mChannelStatus, mData, mOffset, mCount);
  314. }
  315. private:
  316. FTPChannelChild* mChild;
  317. nsresult mChannelStatus;
  318. nsCString mData;
  319. uint64_t mOffset;
  320. uint32_t mCount;
  321. };
  322. bool
  323. FTPChannelChild::RecvOnDataAvailable(const nsresult& channelStatus,
  324. const nsCString& data,
  325. const uint64_t& offset,
  326. const uint32_t& count)
  327. {
  328. MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
  329. "Should not be receiving any more callbacks from parent!");
  330. LOG(("FTPChannelChild::RecvOnDataAvailable [this=%p]\n", this));
  331. mEventQ->RunOrEnqueue(new FTPDataAvailableEvent(this, channelStatus, data,
  332. offset, count),
  333. mDivertingToParent);
  334. return true;
  335. }
  336. class MaybeDivertOnDataFTPEvent : public ChannelEvent
  337. {
  338. public:
  339. MaybeDivertOnDataFTPEvent(FTPChannelChild* child,
  340. const nsCString& data,
  341. const uint64_t& offset,
  342. const uint32_t& count)
  343. : mChild(child)
  344. , mData(data)
  345. , mOffset(offset)
  346. , mCount(count) {}
  347. void Run()
  348. {
  349. mChild->MaybeDivertOnData(mData, mOffset, mCount);
  350. }
  351. private:
  352. FTPChannelChild* mChild;
  353. nsCString mData;
  354. uint64_t mOffset;
  355. uint32_t mCount;
  356. };
  357. void
  358. FTPChannelChild::MaybeDivertOnData(const nsCString& data,
  359. const uint64_t& offset,
  360. const uint32_t& count)
  361. {
  362. if (mDivertingToParent) {
  363. SendDivertOnDataAvailable(data, offset, count);
  364. }
  365. }
  366. void
  367. FTPChannelChild::DoOnDataAvailable(const nsresult& channelStatus,
  368. const nsCString& data,
  369. const uint64_t& offset,
  370. const uint32_t& count)
  371. {
  372. LOG(("FTPChannelChild::DoOnDataAvailable [this=%p]\n", this));
  373. if (!mCanceled && NS_SUCCEEDED(mStatus)) {
  374. mStatus = channelStatus;
  375. }
  376. if (mDivertingToParent) {
  377. MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
  378. "Should not be processing any more callbacks from parent!");
  379. SendDivertOnDataAvailable(data, offset, count);
  380. return;
  381. }
  382. if (mCanceled)
  383. return;
  384. if (mUnknownDecoderInvolved) {
  385. mUnknownDecoderEventQ.AppendElement(
  386. MakeUnique<MaybeDivertOnDataFTPEvent>(this, data, offset, count));
  387. }
  388. // NOTE: the OnDataAvailable contract requires the client to read all the data
  389. // in the inputstream. This code relies on that ('data' will go away after
  390. // this function). Apparently the previous, non-e10s behavior was to actually
  391. // support only reading part of the data, allowing later calls to read the
  392. // rest.
  393. nsCOMPtr<nsIInputStream> stringStream;
  394. nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream),
  395. data.get(),
  396. count,
  397. NS_ASSIGNMENT_DEPEND);
  398. if (NS_FAILED(rv)) {
  399. Cancel(rv);
  400. return;
  401. }
  402. AutoEventEnqueuer ensureSerialDispatch(mEventQ);
  403. rv = mListener->OnDataAvailable(this, mListenerContext,
  404. stringStream, offset, count);
  405. if (NS_FAILED(rv))
  406. Cancel(rv);
  407. stringStream->Close();
  408. }
  409. class FTPStopRequestEvent : public ChannelEvent
  410. {
  411. public:
  412. FTPStopRequestEvent(FTPChannelChild* aChild,
  413. const nsresult& aChannelStatus,
  414. const nsCString &aErrorMsg,
  415. bool aUseUTF8)
  416. : mChild(aChild)
  417. , mChannelStatus(aChannelStatus)
  418. , mErrorMsg(aErrorMsg)
  419. , mUseUTF8(aUseUTF8)
  420. {
  421. }
  422. void Run()
  423. {
  424. mChild->DoOnStopRequest(mChannelStatus, mErrorMsg, mUseUTF8);
  425. }
  426. private:
  427. FTPChannelChild* mChild;
  428. nsresult mChannelStatus;
  429. nsCString mErrorMsg;
  430. bool mUseUTF8;
  431. };
  432. bool
  433. FTPChannelChild::RecvOnStopRequest(const nsresult& aChannelStatus,
  434. const nsCString &aErrorMsg,
  435. const bool &aUseUTF8)
  436. {
  437. MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
  438. "Should not be receiving any more callbacks from parent!");
  439. LOG(("FTPChannelChild::RecvOnStopRequest [this=%p status=%x]\n",
  440. this, aChannelStatus));
  441. mEventQ->RunOrEnqueue(new FTPStopRequestEvent(this, aChannelStatus, aErrorMsg,
  442. aUseUTF8));
  443. return true;
  444. }
  445. class MaybeDivertOnStopFTPEvent : public ChannelEvent
  446. {
  447. public:
  448. MaybeDivertOnStopFTPEvent(FTPChannelChild* child,
  449. const nsresult& aChannelStatus)
  450. : mChild(child)
  451. , mChannelStatus(aChannelStatus) {}
  452. void Run()
  453. {
  454. mChild->MaybeDivertOnStop(mChannelStatus);
  455. }
  456. private:
  457. FTPChannelChild* mChild;
  458. nsresult mChannelStatus;
  459. };
  460. void
  461. FTPChannelChild::MaybeDivertOnStop(const nsresult& aChannelStatus)
  462. {
  463. if (mDivertingToParent) {
  464. SendDivertOnStopRequest(aChannelStatus);
  465. }
  466. }
  467. void
  468. FTPChannelChild::DoOnStopRequest(const nsresult& aChannelStatus,
  469. const nsCString &aErrorMsg,
  470. bool aUseUTF8)
  471. {
  472. LOG(("FTPChannelChild::DoOnStopRequest [this=%p status=%x]\n",
  473. this, aChannelStatus));
  474. if (mDivertingToParent) {
  475. MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
  476. "Should not be processing any more callbacks from parent!");
  477. SendDivertOnStopRequest(aChannelStatus);
  478. return;
  479. }
  480. if (!mCanceled)
  481. mStatus = aChannelStatus;
  482. if (mUnknownDecoderInvolved) {
  483. mUnknownDecoderEventQ.AppendElement(
  484. MakeUnique<MaybeDivertOnStopFTPEvent>(this, aChannelStatus));
  485. }
  486. { // Ensure that all queued ipdl events are dispatched before
  487. // we initiate protocol deletion below.
  488. mIsPending = false;
  489. AutoEventEnqueuer ensureSerialDispatch(mEventQ);
  490. (void)mListener->OnStopRequest(this, mListenerContext, aChannelStatus);
  491. if (NS_FAILED(aChannelStatus) && !aErrorMsg.IsEmpty()) {
  492. NS_ERROR("FTP error on stop request.");
  493. }
  494. mListener = nullptr;
  495. mListenerContext = nullptr;
  496. if (mLoadGroup)
  497. mLoadGroup->RemoveRequest(this, nullptr, aChannelStatus);
  498. }
  499. // This calls NeckoChild::DeallocPFTPChannelChild(), which deletes |this| if IPDL
  500. // holds the last reference. Don't rely on |this| existing after here!
  501. Send__delete__(this);
  502. }
  503. class FTPFailedAsyncOpenEvent : public ChannelEvent
  504. {
  505. public:
  506. FTPFailedAsyncOpenEvent(FTPChannelChild* aChild, nsresult aStatus)
  507. : mChild(aChild), mStatus(aStatus) {}
  508. void Run() { mChild->DoFailedAsyncOpen(mStatus); }
  509. private:
  510. FTPChannelChild* mChild;
  511. nsresult mStatus;
  512. };
  513. bool
  514. FTPChannelChild::RecvFailedAsyncOpen(const nsresult& statusCode)
  515. {
  516. LOG(("FTPChannelChild::RecvFailedAsyncOpen [this=%p status=%x]\n",
  517. this, statusCode));
  518. mEventQ->RunOrEnqueue(new FTPFailedAsyncOpenEvent(this, statusCode));
  519. return true;
  520. }
  521. void
  522. FTPChannelChild::DoFailedAsyncOpen(const nsresult& statusCode)
  523. {
  524. LOG(("FTPChannelChild::DoFailedAsyncOpen [this=%p status=%x]\n",
  525. this, statusCode));
  526. mStatus = statusCode;
  527. if (mLoadGroup)
  528. mLoadGroup->RemoveRequest(this, nullptr, statusCode);
  529. if (mListener) {
  530. mListener->OnStartRequest(this, mListenerContext);
  531. mIsPending = false;
  532. mListener->OnStopRequest(this, mListenerContext, statusCode);
  533. } else {
  534. mIsPending = false;
  535. }
  536. mListener = nullptr;
  537. mListenerContext = nullptr;
  538. if (mIPCOpen)
  539. Send__delete__(this);
  540. }
  541. class FTPFlushedForDiversionEvent : public ChannelEvent
  542. {
  543. public:
  544. explicit FTPFlushedForDiversionEvent(FTPChannelChild* aChild)
  545. : mChild(aChild)
  546. {
  547. MOZ_RELEASE_ASSERT(aChild);
  548. }
  549. void Run()
  550. {
  551. mChild->FlushedForDiversion();
  552. }
  553. private:
  554. FTPChannelChild* mChild;
  555. };
  556. bool
  557. FTPChannelChild::RecvFlushedForDiversion()
  558. {
  559. LOG(("FTPChannelChild::RecvFlushedForDiversion [this=%p]\n", this));
  560. MOZ_ASSERT(mDivertingToParent);
  561. mEventQ->RunOrEnqueue(new FTPFlushedForDiversionEvent(this), true);
  562. return true;
  563. }
  564. void
  565. FTPChannelChild::FlushedForDiversion()
  566. {
  567. LOG(("FTPChannelChild::FlushedForDiversion [this=%p]\n", this));
  568. MOZ_RELEASE_ASSERT(mDivertingToParent);
  569. // Once this is set, it should not be unset before FTPChannelChild is taken
  570. // down. After it is set, no OnStart/OnData/OnStop callbacks should be
  571. // received from the parent channel, nor dequeued from the ChannelEventQueue.
  572. mFlushedForDiversion = true;
  573. SendDivertComplete();
  574. }
  575. bool
  576. FTPChannelChild::RecvDivertMessages()
  577. {
  578. LOG(("FTPChannelChild::RecvDivertMessages [this=%p]\n", this));
  579. MOZ_RELEASE_ASSERT(mDivertingToParent);
  580. MOZ_RELEASE_ASSERT(mSuspendCount > 0);
  581. // DivertTo() has been called on parent, so we can now start sending queued
  582. // IPDL messages back to parent listener.
  583. if (NS_WARN_IF(NS_FAILED(Resume()))) {
  584. return false;
  585. }
  586. return true;
  587. }
  588. class FTPDeleteSelfEvent : public ChannelEvent
  589. {
  590. public:
  591. explicit FTPDeleteSelfEvent(FTPChannelChild* aChild)
  592. : mChild(aChild) {}
  593. void Run() { mChild->DoDeleteSelf(); }
  594. private:
  595. FTPChannelChild* mChild;
  596. };
  597. bool
  598. FTPChannelChild::RecvDeleteSelf()
  599. {
  600. mEventQ->RunOrEnqueue(new FTPDeleteSelfEvent(this));
  601. return true;
  602. }
  603. void
  604. FTPChannelChild::DoDeleteSelf()
  605. {
  606. if (mIPCOpen)
  607. Send__delete__(this);
  608. }
  609. NS_IMETHODIMP
  610. FTPChannelChild::Cancel(nsresult status)
  611. {
  612. LOG(("FTPChannelChild::Cancel [this=%p]\n", this));
  613. if (mCanceled)
  614. return NS_OK;
  615. mCanceled = true;
  616. mStatus = status;
  617. if (mIPCOpen)
  618. SendCancel(status);
  619. return NS_OK;
  620. }
  621. NS_IMETHODIMP
  622. FTPChannelChild::Suspend()
  623. {
  624. NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_NOT_AVAILABLE);
  625. LOG(("FTPChannelChild::Suspend [this=%p]\n", this));
  626. // SendSuspend only once, when suspend goes from 0 to 1.
  627. // Don't SendSuspend at all if we're diverting callbacks to the parent;
  628. // suspend will be called at the correct time in the parent itself.
  629. if (!mSuspendCount++ && !mDivertingToParent) {
  630. SendSuspend();
  631. mSuspendSent = true;
  632. }
  633. mEventQ->Suspend();
  634. return NS_OK;
  635. }
  636. NS_IMETHODIMP
  637. FTPChannelChild::Resume()
  638. {
  639. NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_NOT_AVAILABLE);
  640. LOG(("FTPChannelChild::Resume [this=%p]\n", this));
  641. // SendResume only once, when suspend count drops to 0.
  642. // Don't SendResume at all if we're diverting callbacks to the parent (unless
  643. // suspend was sent earlier); otherwise, resume will be called at the correct
  644. // time in the parent itself.
  645. if (!--mSuspendCount && (!mDivertingToParent || mSuspendSent)) {
  646. SendResume();
  647. }
  648. mEventQ->Resume();
  649. return NS_OK;
  650. }
  651. //-----------------------------------------------------------------------------
  652. // FTPChannelChild::nsIChildChannel
  653. //-----------------------------------------------------------------------------
  654. NS_IMETHODIMP
  655. FTPChannelChild::ConnectParent(uint32_t id)
  656. {
  657. LOG(("FTPChannelChild::ConnectParent [this=%p]\n", this));
  658. mozilla::dom::TabChild* tabChild = nullptr;
  659. nsCOMPtr<nsITabChild> iTabChild;
  660. NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
  661. NS_GET_IID(nsITabChild),
  662. getter_AddRefs(iTabChild));
  663. GetCallback(iTabChild);
  664. if (iTabChild) {
  665. tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
  666. }
  667. // The socket transport in the chrome process now holds a logical ref to us
  668. // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
  669. AddIPDLReference();
  670. FTPChannelConnectArgs connectArgs(id);
  671. if (!gNeckoChild->SendPFTPChannelConstructor(this, tabChild,
  672. IPC::SerializedLoadContext(this),
  673. connectArgs)) {
  674. return NS_ERROR_FAILURE;
  675. }
  676. return NS_OK;
  677. }
  678. NS_IMETHODIMP
  679. FTPChannelChild::CompleteRedirectSetup(nsIStreamListener *listener,
  680. nsISupports *aContext)
  681. {
  682. LOG(("FTPChannelChild::CompleteRedirectSetup [this=%p]\n", this));
  683. NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
  684. NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
  685. mIsPending = true;
  686. mWasOpened = true;
  687. mListener = listener;
  688. mListenerContext = aContext;
  689. // add ourselves to the load group.
  690. if (mLoadGroup)
  691. mLoadGroup->AddRequest(this, nullptr);
  692. // We already have an open IPDL connection to the parent. If on-modify-request
  693. // listeners or load group observers canceled us, let the parent handle it
  694. // and send it back to us naturally.
  695. return NS_OK;
  696. }
  697. //-----------------------------------------------------------------------------
  698. // FTPChannelChild::nsIDivertableChannel
  699. //-----------------------------------------------------------------------------
  700. NS_IMETHODIMP
  701. FTPChannelChild::DivertToParent(ChannelDiverterChild **aChild)
  702. {
  703. MOZ_RELEASE_ASSERT(aChild);
  704. MOZ_RELEASE_ASSERT(gNeckoChild);
  705. MOZ_RELEASE_ASSERT(!mDivertingToParent);
  706. LOG(("FTPChannelChild::DivertToParent [this=%p]\n", this));
  707. // We must fail DivertToParent() if there's no parent end of the channel (and
  708. // won't be!) due to early failure.
  709. if (NS_FAILED(mStatus) && !mIPCOpen) {
  710. return mStatus;
  711. }
  712. nsresult rv = Suspend();
  713. if (NS_WARN_IF(NS_FAILED(rv))) {
  714. return rv;
  715. }
  716. // Once this is set, it should not be unset before the child is taken down.
  717. mDivertingToParent = true;
  718. PChannelDiverterChild* diverter =
  719. gNeckoChild->SendPChannelDiverterConstructor(this);
  720. MOZ_RELEASE_ASSERT(diverter);
  721. *aChild = static_cast<ChannelDiverterChild*>(diverter);
  722. return NS_OK;
  723. }
  724. NS_IMETHODIMP
  725. FTPChannelChild::UnknownDecoderInvolvedKeepData()
  726. {
  727. mUnknownDecoderInvolved = true;
  728. return NS_OK;
  729. }
  730. NS_IMETHODIMP
  731. FTPChannelChild::UnknownDecoderInvolvedOnStartRequestCalled()
  732. {
  733. mUnknownDecoderInvolved = false;
  734. nsresult rv = NS_OK;
  735. if (mDivertingToParent) {
  736. rv = mEventQ->PrependEvents(mUnknownDecoderEventQ);
  737. }
  738. mUnknownDecoderEventQ.Clear();
  739. return rv;
  740. }
  741. NS_IMETHODIMP
  742. FTPChannelChild::GetDivertingToParent(bool* aDiverting)
  743. {
  744. NS_ENSURE_ARG_POINTER(aDiverting);
  745. *aDiverting = mDivertingToParent;
  746. return NS_OK;
  747. }
  748. } // namespace net
  749. } // namespace mozilla