nsDocLoader.cpp 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593
  1. /* -*- Mode: C++; tab-width: 2; 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 "nspr.h"
  6. #include "mozilla/BasicEvents.h"
  7. #include "mozilla/EventDispatcher.h"
  8. #include "mozilla/Logging.h"
  9. #include "nsDocLoader.h"
  10. #include "nsCURILoader.h"
  11. #include "nsNetUtil.h"
  12. #include "nsIHttpChannel.h"
  13. #include "nsIWebProgressListener2.h"
  14. #include "nsIServiceManager.h"
  15. #include "nsXPIDLString.h"
  16. #include "nsIURL.h"
  17. #include "nsCOMPtr.h"
  18. #include "nscore.h"
  19. #include "nsWeakPtr.h"
  20. #include "nsAutoPtr.h"
  21. #include "nsQueryObject.h"
  22. #include "nsIDOMWindow.h"
  23. #include "nsPIDOMWindow.h"
  24. #include "nsIStringBundle.h"
  25. #include "nsIScriptSecurityManager.h"
  26. #include "nsITransport.h"
  27. #include "nsISocketTransport.h"
  28. #include "nsIDocShell.h"
  29. #include "nsIDOMDocument.h"
  30. #include "nsIDocument.h"
  31. #include "nsPresContext.h"
  32. #include "nsIAsyncVerifyRedirectCallback.h"
  33. using mozilla::DebugOnly;
  34. using mozilla::eLoad;
  35. using mozilla::EventDispatcher;
  36. using mozilla::LogLevel;
  37. using mozilla::WidgetEvent;
  38. static NS_DEFINE_CID(kThisImplCID, NS_THIS_DOCLOADER_IMPL_CID);
  39. //
  40. // Log module for nsIDocumentLoader logging...
  41. //
  42. // To enable logging (see mozilla/Logging.h for full details):
  43. //
  44. // set MOZ_LOG=DocLoader:5
  45. // set MOZ_LOG_FILE=debug.log
  46. //
  47. // this enables LogLevel::Debug level information and places all output in
  48. // the file 'debug.log'.
  49. //
  50. mozilla::LazyLogModule gDocLoaderLog("DocLoader");
  51. #if defined(DEBUG)
  52. void GetURIStringFromRequest(nsIRequest* request, nsACString &name)
  53. {
  54. if (request)
  55. request->GetName(name);
  56. else
  57. name.AssignLiteral("???");
  58. }
  59. #endif /* DEBUG */
  60. void
  61. nsDocLoader::RequestInfoHashInitEntry(PLDHashEntryHdr* entry,
  62. const void* key)
  63. {
  64. // Initialize the entry with placement new
  65. new (entry) nsRequestInfo(key);
  66. }
  67. void
  68. nsDocLoader::RequestInfoHashClearEntry(PLDHashTable* table,
  69. PLDHashEntryHdr* entry)
  70. {
  71. nsRequestInfo* info = static_cast<nsRequestInfo *>(entry);
  72. info->~nsRequestInfo();
  73. }
  74. // this is used for mListenerInfoList.Contains()
  75. template <>
  76. class nsDefaultComparator <nsDocLoader::nsListenerInfo, nsIWebProgressListener*> {
  77. public:
  78. bool Equals(const nsDocLoader::nsListenerInfo& aInfo,
  79. nsIWebProgressListener* const& aListener) const {
  80. nsCOMPtr<nsIWebProgressListener> listener =
  81. do_QueryReferent(aInfo.mWeakListener);
  82. return aListener == listener;
  83. }
  84. };
  85. /* static */ const PLDHashTableOps nsDocLoader::sRequestInfoHashOps =
  86. {
  87. PLDHashTable::HashVoidPtrKeyStub,
  88. PLDHashTable::MatchEntryStub,
  89. PLDHashTable::MoveEntryStub,
  90. nsDocLoader::RequestInfoHashClearEntry,
  91. nsDocLoader::RequestInfoHashInitEntry
  92. };
  93. nsDocLoader::nsDocLoader()
  94. : mParent(nullptr),
  95. mCurrentSelfProgress(0),
  96. mMaxSelfProgress(0),
  97. mCurrentTotalProgress(0),
  98. mMaxTotalProgress(0),
  99. mRequestInfoHash(&sRequestInfoHashOps, sizeof(nsRequestInfo)),
  100. mCompletedTotalProgress(0),
  101. mIsLoadingDocument(false),
  102. mIsRestoringDocument(false),
  103. mDontFlushLayout(false),
  104. mIsFlushingLayout(false),
  105. mDocumentOpenedButNotLoaded(false)
  106. {
  107. ClearInternalProgress();
  108. MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
  109. ("DocLoader:%p: created.\n", this));
  110. }
  111. nsresult
  112. nsDocLoader::SetDocLoaderParent(nsDocLoader *aParent)
  113. {
  114. mParent = aParent;
  115. return NS_OK;
  116. }
  117. nsresult
  118. nsDocLoader::Init()
  119. {
  120. nsresult rv = NS_NewLoadGroup(getter_AddRefs(mLoadGroup), this);
  121. if (NS_FAILED(rv)) return rv;
  122. MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
  123. ("DocLoader:%p: load group %x.\n", this, mLoadGroup.get()));
  124. return NS_OK;
  125. }
  126. nsDocLoader::~nsDocLoader()
  127. {
  128. /*
  129. |ClearWeakReferences()| here is intended to prevent people holding weak references
  130. from re-entering this destructor since |QueryReferent()| will |AddRef()| me, and the
  131. subsequent |Release()| will try to destroy me. At this point there should be only
  132. weak references remaining (otherwise, we wouldn't be getting destroyed).
  133. An alternative would be incrementing our refcount (consider it a compressed flag
  134. saying "Don't re-destroy."). I haven't yet decided which is better. [scc]
  135. */
  136. // XXXbz now that NS_IMPL_RELEASE stabilizes by setting refcount to 1, is
  137. // this needed?
  138. ClearWeakReferences();
  139. Destroy();
  140. MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
  141. ("DocLoader:%p: deleted.\n", this));
  142. }
  143. /*
  144. * Implementation of ISupports methods...
  145. */
  146. NS_IMPL_ADDREF(nsDocLoader)
  147. NS_IMPL_RELEASE(nsDocLoader)
  148. NS_INTERFACE_MAP_BEGIN(nsDocLoader)
  149. NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRequestObserver)
  150. NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
  151. NS_INTERFACE_MAP_ENTRY(nsIDocumentLoader)
  152. NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
  153. NS_INTERFACE_MAP_ENTRY(nsIWebProgress)
  154. NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
  155. NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
  156. NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
  157. NS_INTERFACE_MAP_ENTRY(nsISecurityEventSink)
  158. NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
  159. if (aIID.Equals(kThisImplCID))
  160. foundInterface = static_cast<nsIDocumentLoader *>(this);
  161. else
  162. NS_INTERFACE_MAP_END
  163. /*
  164. * Implementation of nsIInterfaceRequestor methods...
  165. */
  166. NS_IMETHODIMP nsDocLoader::GetInterface(const nsIID& aIID, void** aSink)
  167. {
  168. nsresult rv = NS_ERROR_NO_INTERFACE;
  169. NS_ENSURE_ARG_POINTER(aSink);
  170. if(aIID.Equals(NS_GET_IID(nsILoadGroup))) {
  171. *aSink = mLoadGroup;
  172. NS_IF_ADDREF((nsISupports*)*aSink);
  173. rv = NS_OK;
  174. } else {
  175. rv = QueryInterface(aIID, aSink);
  176. }
  177. return rv;
  178. }
  179. /* static */
  180. already_AddRefed<nsDocLoader>
  181. nsDocLoader::GetAsDocLoader(nsISupports* aSupports)
  182. {
  183. RefPtr<nsDocLoader> ret = do_QueryObject(aSupports);
  184. return ret.forget();
  185. }
  186. /* static */
  187. nsresult
  188. nsDocLoader::AddDocLoaderAsChildOfRoot(nsDocLoader* aDocLoader)
  189. {
  190. nsresult rv;
  191. nsCOMPtr<nsIDocumentLoader> docLoaderService =
  192. do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID, &rv);
  193. NS_ENSURE_SUCCESS(rv, rv);
  194. RefPtr<nsDocLoader> rootDocLoader = GetAsDocLoader(docLoaderService);
  195. NS_ENSURE_TRUE(rootDocLoader, NS_ERROR_UNEXPECTED);
  196. return rootDocLoader->AddChildLoader(aDocLoader);
  197. }
  198. NS_IMETHODIMP
  199. nsDocLoader::Stop(void)
  200. {
  201. nsresult rv = NS_OK;
  202. MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
  203. ("DocLoader:%p: Stop() called\n", this));
  204. NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mChildList, nsDocLoader, Stop, ());
  205. if (mLoadGroup)
  206. rv = mLoadGroup->Cancel(NS_BINDING_ABORTED);
  207. // Don't report that we're flushing layout so IsBusy returns false after a
  208. // Stop call.
  209. mIsFlushingLayout = false;
  210. // Clear out mChildrenInOnload. We want to make sure to fire our
  211. // onload at this point, and there's no issue with mChildrenInOnload
  212. // after this, since mDocumentRequest will be null after the
  213. // DocLoaderIsEmpty() call.
  214. mChildrenInOnload.Clear();
  215. // Make sure to call DocLoaderIsEmpty now so that we reset mDocumentRequest,
  216. // etc, as needed. We could be getting into here from a subframe onload, in
  217. // which case the call to DocLoaderIsEmpty() is coming but hasn't quite
  218. // happened yet, Canceling the loadgroup did nothing (because it was already
  219. // empty), and we're about to start a new load (which is what triggered this
  220. // Stop() call).
  221. // XXXbz If the child frame loadgroups were requests in mLoadgroup, I suspect
  222. // we wouldn't need the call here....
  223. NS_ASSERTION(!IsBusy(), "Shouldn't be busy here");
  224. DocLoaderIsEmpty(false);
  225. return rv;
  226. }
  227. bool
  228. nsDocLoader::IsBusy()
  229. {
  230. nsresult rv;
  231. //
  232. // A document loader is busy if either:
  233. //
  234. // 1. One of its children is in the middle of an onload handler. Note that
  235. // the handler may have already removed this child from mChildList!
  236. // 2. It is currently loading a document and either has parts of it still
  237. // loading, or has a busy child docloader.
  238. // 3. It's currently flushing layout in DocLoaderIsEmpty().
  239. //
  240. if (mChildrenInOnload.Count() || mIsFlushingLayout) {
  241. return true;
  242. }
  243. /* Is this document loader busy? */
  244. if (!IsBlockingLoadEvent()) {
  245. return false;
  246. }
  247. bool busy;
  248. rv = mLoadGroup->IsPending(&busy);
  249. if (NS_FAILED(rv)) {
  250. return false;
  251. }
  252. if (busy) {
  253. return true;
  254. }
  255. /* check its child document loaders... */
  256. uint32_t count = mChildList.Length();
  257. for (uint32_t i=0; i < count; i++) {
  258. nsIDocumentLoader* loader = ChildAt(i);
  259. // This is a safe cast, because we only put nsDocLoader objects into the
  260. // array
  261. if (loader && static_cast<nsDocLoader*>(loader)->IsBusy())
  262. return true;
  263. }
  264. return false;
  265. }
  266. NS_IMETHODIMP
  267. nsDocLoader::GetContainer(nsISupports** aResult)
  268. {
  269. NS_ADDREF(*aResult = static_cast<nsIDocumentLoader*>(this));
  270. return NS_OK;
  271. }
  272. NS_IMETHODIMP
  273. nsDocLoader::GetLoadGroup(nsILoadGroup** aResult)
  274. {
  275. nsresult rv = NS_OK;
  276. if (nullptr == aResult) {
  277. rv = NS_ERROR_NULL_POINTER;
  278. } else {
  279. *aResult = mLoadGroup;
  280. NS_IF_ADDREF(*aResult);
  281. }
  282. return rv;
  283. }
  284. void
  285. nsDocLoader::Destroy()
  286. {
  287. Stop();
  288. // Remove the document loader from the parent list of loaders...
  289. if (mParent)
  290. {
  291. DebugOnly<nsresult> rv = mParent->RemoveChildLoader(this);
  292. NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "RemoveChildLoader failed");
  293. }
  294. // Release all the information about network requests...
  295. ClearRequestInfoHash();
  296. mListenerInfoList.Clear();
  297. mListenerInfoList.Compact();
  298. mDocumentRequest = nullptr;
  299. if (mLoadGroup)
  300. mLoadGroup->SetGroupObserver(nullptr);
  301. DestroyChildren();
  302. }
  303. void
  304. nsDocLoader::DestroyChildren()
  305. {
  306. uint32_t count = mChildList.Length();
  307. // if the doc loader still has children...we need to enumerate the
  308. // children and make them null out their back ptr to the parent doc
  309. // loader
  310. for (uint32_t i=0; i < count; i++)
  311. {
  312. nsIDocumentLoader* loader = ChildAt(i);
  313. if (loader) {
  314. // This is a safe cast, as we only put nsDocLoader objects into the
  315. // array
  316. DebugOnly<nsresult> rv =
  317. static_cast<nsDocLoader*>(loader)->SetDocLoaderParent(nullptr);
  318. NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetDocLoaderParent failed");
  319. }
  320. }
  321. mChildList.Clear();
  322. }
  323. NS_IMETHODIMP
  324. nsDocLoader::OnStartRequest(nsIRequest *request, nsISupports *aCtxt)
  325. {
  326. // called each time a request is added to the group.
  327. if (MOZ_LOG_TEST(gDocLoaderLog, LogLevel::Debug)) {
  328. nsAutoCString name;
  329. request->GetName(name);
  330. uint32_t count = 0;
  331. if (mLoadGroup)
  332. mLoadGroup->GetActiveCount(&count);
  333. MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
  334. ("DocLoader:%p: OnStartRequest[%p](%s) mIsLoadingDocument=%s, %u active URLs",
  335. this, request, name.get(),
  336. (mIsLoadingDocument ? "true" : "false"),
  337. count));
  338. }
  339. bool bJustStartedLoading = false;
  340. nsLoadFlags loadFlags = 0;
  341. request->GetLoadFlags(&loadFlags);
  342. if (!mIsLoadingDocument && (loadFlags & nsIChannel::LOAD_DOCUMENT_URI)) {
  343. bJustStartedLoading = true;
  344. mIsLoadingDocument = true;
  345. mDocumentOpenedButNotLoaded = false;
  346. ClearInternalProgress(); // only clear our progress if we are starting a new load....
  347. }
  348. //
  349. // Create a new nsRequestInfo for the request that is starting to
  350. // load...
  351. //
  352. AddRequestInfo(request);
  353. //
  354. // Only fire a doStartDocumentLoad(...) if the document loader
  355. // has initiated a load... Otherwise, this notification has
  356. // resulted from a request being added to the load group.
  357. //
  358. if (mIsLoadingDocument) {
  359. if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI) {
  360. //
  361. // Make sure that the document channel is null at this point...
  362. // (unless its been redirected)
  363. //
  364. NS_ASSERTION((loadFlags & nsIChannel::LOAD_REPLACE) ||
  365. !(mDocumentRequest.get()),
  366. "Overwriting an existing document channel!");
  367. // This request is associated with the entire document...
  368. mDocumentRequest = request;
  369. mLoadGroup->SetDefaultLoadRequest(request);
  370. // Only fire the start document load notification for the first
  371. // document URI... Do not fire it again for redirections
  372. //
  373. if (bJustStartedLoading) {
  374. // Update the progress status state
  375. mProgressStateFlags = nsIWebProgressListener::STATE_START;
  376. // Fire the start document load notification
  377. doStartDocumentLoad();
  378. return NS_OK;
  379. }
  380. }
  381. }
  382. NS_ASSERTION(!mIsLoadingDocument || mDocumentRequest,
  383. "mDocumentRequest MUST be set for the duration of a page load!");
  384. doStartURLLoad(request);
  385. return NS_OK;
  386. }
  387. NS_IMETHODIMP
  388. nsDocLoader::OnStopRequest(nsIRequest *aRequest,
  389. nsISupports *aCtxt,
  390. nsresult aStatus)
  391. {
  392. nsresult rv = NS_OK;
  393. if (MOZ_LOG_TEST(gDocLoaderLog, LogLevel::Debug)) {
  394. nsAutoCString name;
  395. aRequest->GetName(name);
  396. uint32_t count = 0;
  397. if (mLoadGroup)
  398. mLoadGroup->GetActiveCount(&count);
  399. MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
  400. ("DocLoader:%p: OnStopRequest[%p](%s) status=%x"
  401. "mIsLoadingDocument=%s, mDocumentOpenedButNotLoaded=%s, %u active URLs",
  402. this, aRequest, name.get(),
  403. aStatus, (mIsLoadingDocument ? "true" : "false"),
  404. (mDocumentOpenedButNotLoaded ? "true" : "false"), count));
  405. }
  406. bool bFireTransferring = false;
  407. //
  408. // Set the Maximum progress to the same value as the current progress.
  409. // Since the URI has finished loading, all the data is there. Also,
  410. // this will allow a more accurate estimation of the max progress (in case
  411. // the old value was unknown ie. -1)
  412. //
  413. nsRequestInfo *info = GetRequestInfo(aRequest);
  414. if (info) {
  415. // Null out mLastStatus now so we don't find it when looking for
  416. // status from now on. This destroys the nsStatusInfo and hence
  417. // removes it from our list.
  418. info->mLastStatus = nullptr;
  419. int64_t oldMax = info->mMaxProgress;
  420. info->mMaxProgress = info->mCurrentProgress;
  421. //
  422. // If a request whose content-length was previously unknown has just
  423. // finished loading, then use this new data to try to calculate a
  424. // mMaxSelfProgress...
  425. //
  426. if ((oldMax < int64_t(0)) && (mMaxSelfProgress < int64_t(0))) {
  427. mMaxSelfProgress = CalculateMaxProgress();
  428. }
  429. // As we know the total progress of this request now, save it to be part
  430. // of CalculateMaxProgress() result. We need to remove the info from the
  431. // hash, see bug 480713.
  432. mCompletedTotalProgress += info->mMaxProgress;
  433. //
  434. // Determine whether a STATE_TRANSFERRING notification should be
  435. // 'synthesized'.
  436. //
  437. // If nsRequestInfo::mMaxProgress (as stored in oldMax) and
  438. // nsRequestInfo::mCurrentProgress are both 0, then the
  439. // STATE_TRANSFERRING notification has not been fired yet...
  440. //
  441. if ((oldMax == 0) && (info->mCurrentProgress == 0)) {
  442. nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
  443. // Only fire a TRANSFERRING notification if the request is also a
  444. // channel -- data transfer requires a nsIChannel!
  445. //
  446. if (channel) {
  447. if (NS_SUCCEEDED(aStatus)) {
  448. bFireTransferring = true;
  449. }
  450. //
  451. // If the request failed (for any reason other than being
  452. // redirected or retargeted), the TRANSFERRING notification can
  453. // still be fired if a HTTP connection was established to a server.
  454. //
  455. else if (aStatus != NS_BINDING_REDIRECTED &&
  456. aStatus != NS_BINDING_RETARGETED) {
  457. //
  458. // Only if the load has been targeted (see bug 268483)...
  459. //
  460. uint32_t lf;
  461. channel->GetLoadFlags(&lf);
  462. if (lf & nsIChannel::LOAD_TARGETED) {
  463. nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
  464. if (httpChannel) {
  465. uint32_t responseCode;
  466. rv = httpChannel->GetResponseStatus(&responseCode);
  467. if (NS_SUCCEEDED(rv)) {
  468. //
  469. // A valid server status indicates that a connection was
  470. // established to the server... So, fire the notification
  471. // even though a failure occurred later...
  472. //
  473. bFireTransferring = true;
  474. }
  475. }
  476. }
  477. }
  478. }
  479. }
  480. }
  481. if (bFireTransferring) {
  482. // Send a STATE_TRANSFERRING notification for the request.
  483. int32_t flags;
  484. flags = nsIWebProgressListener::STATE_TRANSFERRING |
  485. nsIWebProgressListener::STATE_IS_REQUEST;
  486. //
  487. // Move the WebProgress into the STATE_TRANSFERRING state if necessary...
  488. //
  489. if (mProgressStateFlags & nsIWebProgressListener::STATE_START) {
  490. mProgressStateFlags = nsIWebProgressListener::STATE_TRANSFERRING;
  491. // Send STATE_TRANSFERRING for the document too...
  492. flags |= nsIWebProgressListener::STATE_IS_DOCUMENT;
  493. }
  494. FireOnStateChange(this, aRequest, flags, NS_OK);
  495. }
  496. //
  497. // Fire the OnStateChange(...) notification for stop request
  498. //
  499. doStopURLLoad(aRequest, aStatus);
  500. // Clear this request out of the hash to avoid bypass of FireOnStateChange
  501. // when address of the request is reused.
  502. RemoveRequestInfo(aRequest);
  503. //
  504. // Only fire the DocLoaderIsEmpty(...) if we may need to fire onload.
  505. //
  506. if (IsBlockingLoadEvent()) {
  507. nsCOMPtr<nsIDocShell> ds = do_QueryInterface(static_cast<nsIRequestObserver*>(this));
  508. bool doNotFlushLayout = false;
  509. if (ds) {
  510. // Don't do unexpected layout flushes while we're in process of restoring
  511. // a document from the bfcache.
  512. ds->GetRestoringDocument(&doNotFlushLayout);
  513. }
  514. DocLoaderIsEmpty(!doNotFlushLayout);
  515. }
  516. return NS_OK;
  517. }
  518. nsresult nsDocLoader::RemoveChildLoader(nsDocLoader* aChild)
  519. {
  520. nsresult rv = mChildList.RemoveElement(aChild) ? NS_OK : NS_ERROR_FAILURE;
  521. if (NS_SUCCEEDED(rv)) {
  522. rv = aChild->SetDocLoaderParent(nullptr);
  523. }
  524. return rv;
  525. }
  526. nsresult nsDocLoader::AddChildLoader(nsDocLoader* aChild)
  527. {
  528. nsresult rv = mChildList.AppendElement(aChild) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
  529. if (NS_SUCCEEDED(rv)) {
  530. rv = aChild->SetDocLoaderParent(this);
  531. }
  532. return rv;
  533. }
  534. NS_IMETHODIMP nsDocLoader::GetDocumentChannel(nsIChannel ** aChannel)
  535. {
  536. if (!mDocumentRequest) {
  537. *aChannel = nullptr;
  538. return NS_OK;
  539. }
  540. return CallQueryInterface(mDocumentRequest, aChannel);
  541. }
  542. void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout)
  543. {
  544. if (IsBlockingLoadEvent()) {
  545. /* In the unimagineably rude circumstance that onload event handlers
  546. triggered by this function actually kill the window ... ok, it's
  547. not unimagineable; it's happened ... this deathgrip keeps this object
  548. alive long enough to survive this function call. */
  549. nsCOMPtr<nsIDocumentLoader> kungFuDeathGrip(this);
  550. // Don't flush layout if we're still busy.
  551. if (IsBusy()) {
  552. return;
  553. }
  554. NS_ASSERTION(!mIsFlushingLayout, "Someone screwed up");
  555. // We may not have a document request if we are in a document.open() situation.
  556. NS_ASSERTION(mDocumentRequest || mDocumentOpenedButNotLoaded,
  557. "No Document Request!");
  558. // The load group for this DocumentLoader is idle. Flush if we need to.
  559. if (aFlushLayout && !mDontFlushLayout) {
  560. nsCOMPtr<nsIDOMDocument> domDoc = do_GetInterface(GetAsSupports(this));
  561. nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
  562. if (doc) {
  563. // We start loads from style resolution, so we need to flush out style
  564. // no matter what. If we have user fonts, we also need to flush layout,
  565. // since the reflow is what starts font loads.
  566. mozFlushType flushType = Flush_Style;
  567. nsIPresShell* shell = doc->GetShell();
  568. if (shell) {
  569. // Be safe in case this presshell is in teardown now
  570. nsPresContext* presContext = shell->GetPresContext();
  571. if (presContext && presContext->GetUserFontSet()) {
  572. flushType = Flush_Layout;
  573. }
  574. }
  575. mDontFlushLayout = mIsFlushingLayout = true;
  576. doc->FlushPendingNotifications(flushType);
  577. mDontFlushLayout = mIsFlushingLayout = false;
  578. }
  579. }
  580. // And now check whether we're really busy; that might have changed with
  581. // the layout flush.
  582. //
  583. // Note, mDocumentRequest can be null while mDocumentOpenedButNotLoaded is
  584. // false if the flushing above re-entered this method. Exit in that case.
  585. if (IsBusy() || (!mDocumentRequest && !mDocumentOpenedButNotLoaded)) {
  586. return;
  587. }
  588. if (mDocumentRequest) {
  589. // Clear out our request info hash, now that our load really is done and
  590. // we don't need it anymore to CalculateMaxProgress().
  591. ClearInternalProgress();
  592. MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
  593. ("DocLoader:%p: Is now idle...\n", this));
  594. nsCOMPtr<nsIRequest> docRequest = mDocumentRequest;
  595. mDocumentRequest = nullptr;
  596. mIsLoadingDocument = false;
  597. // Update the progress status state - the document is done
  598. mProgressStateFlags = nsIWebProgressListener::STATE_STOP;
  599. nsresult loadGroupStatus = NS_OK;
  600. mLoadGroup->GetStatus(&loadGroupStatus);
  601. //
  602. // New code to break the circular reference between
  603. // the load group and the docloader...
  604. //
  605. mLoadGroup->SetDefaultLoadRequest(nullptr);
  606. // Take a ref to our parent now so that we can call ChildDoneWithOnload() on
  607. // it even if our onload handler removes us from the docloader tree.
  608. RefPtr<nsDocLoader> parent = mParent;
  609. // Note that if calling ChildEnteringOnload() on the parent returns false
  610. // then calling our onload handler is not safe. That can only happen on
  611. // OOM, so that's ok.
  612. if (!parent || parent->ChildEnteringOnload(this)) {
  613. // Do nothing with our state after firing the
  614. // OnEndDocumentLoad(...). The document loader may be loading a *new*
  615. // document - if LoadDocument() was called from a handler!
  616. //
  617. doStopDocumentLoad(docRequest, loadGroupStatus);
  618. if (parent) {
  619. parent->ChildDoneWithOnload(this);
  620. }
  621. }
  622. } else {
  623. MOZ_ASSERT(mDocumentOpenedButNotLoaded);
  624. mDocumentOpenedButNotLoaded = false;
  625. // Make sure we do the ChildEnteringOnload/ChildDoneWithOnload even if we
  626. // plan to skip firing our own load event, because otherwise we might
  627. // never end up firing our parent's load event.
  628. RefPtr<nsDocLoader> parent = mParent;
  629. if (!parent || parent->ChildEnteringOnload(this)) {
  630. nsresult loadGroupStatus = NS_OK;
  631. mLoadGroup->GetStatus(&loadGroupStatus);
  632. // Make sure we're not canceling the loadgroup. If we are, then we should
  633. // not fire a load event just like in the normal navigation case.
  634. if (NS_SUCCEEDED(loadGroupStatus) ||
  635. loadGroupStatus == NS_ERROR_PARSED_DATA_CACHED) {
  636. // Can "doc" or "window" ever come back null here? Our state machine
  637. // is complicated enough, so I wouldn't bet against it...
  638. nsCOMPtr<nsIDocument> doc = do_GetInterface(GetAsSupports(this));
  639. if (doc) {
  640. doc->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE,
  641. /* updateTimingInformation = */ false);
  642. nsCOMPtr<nsPIDOMWindowOuter> window = doc->GetWindow();
  643. if (window && !doc->SkipLoadEventAfterClose()) {
  644. MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
  645. ("DocLoader:%p: Firing load event for document.open\n",
  646. this));
  647. // This is a very cut-down version of
  648. // nsDocumentViewer::LoadComplete that doesn't do various things
  649. // that are not relevant here because this wasn't an actual
  650. // navigation.
  651. WidgetEvent event(true, eLoad);
  652. event.mFlags.mBubbles = false;
  653. event.mFlags.mCancelable = false;
  654. // Dispatching to |window|, but using |document| as the target,
  655. // per spec.
  656. event.mTarget = doc;
  657. nsEventStatus unused = nsEventStatus_eIgnore;
  658. doc->SetLoadEventFiring(true);
  659. EventDispatcher::Dispatch(window, nullptr, &event, nullptr,
  660. &unused);
  661. doc->SetLoadEventFiring(false);
  662. // Now unsuppress painting on the presshell, if we
  663. // haven't done that yet.
  664. nsCOMPtr<nsIPresShell> shell = doc->GetShell();
  665. if (shell && !shell->IsDestroying()) {
  666. shell->UnsuppressPainting();
  667. if (!shell->IsDestroying()) {
  668. shell->LoadComplete();
  669. }
  670. }
  671. }
  672. }
  673. }
  674. if (parent) {
  675. parent->ChildDoneWithOnload(this);
  676. }
  677. }
  678. }
  679. }
  680. }
  681. void nsDocLoader::doStartDocumentLoad(void)
  682. {
  683. #if defined(DEBUG)
  684. nsAutoCString buffer;
  685. GetURIStringFromRequest(mDocumentRequest, buffer);
  686. MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
  687. ("DocLoader:%p: ++ Firing OnStateChange for start document load (...)."
  688. "\tURI: %s \n",
  689. this, buffer.get()));
  690. #endif /* DEBUG */
  691. // Fire an OnStatus(...) notification STATE_START. This indicates
  692. // that the document represented by mDocumentRequest has started to
  693. // load...
  694. FireOnStateChange(this,
  695. mDocumentRequest,
  696. nsIWebProgressListener::STATE_START |
  697. nsIWebProgressListener::STATE_IS_DOCUMENT |
  698. nsIWebProgressListener::STATE_IS_REQUEST |
  699. nsIWebProgressListener::STATE_IS_WINDOW |
  700. nsIWebProgressListener::STATE_IS_NETWORK,
  701. NS_OK);
  702. }
  703. void nsDocLoader::doStartURLLoad(nsIRequest *request)
  704. {
  705. #if defined(DEBUG)
  706. nsAutoCString buffer;
  707. GetURIStringFromRequest(request, buffer);
  708. MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
  709. ("DocLoader:%p: ++ Firing OnStateChange start url load (...)."
  710. "\tURI: %s\n",
  711. this, buffer.get()));
  712. #endif /* DEBUG */
  713. FireOnStateChange(this,
  714. request,
  715. nsIWebProgressListener::STATE_START |
  716. nsIWebProgressListener::STATE_IS_REQUEST,
  717. NS_OK);
  718. }
  719. void nsDocLoader::doStopURLLoad(nsIRequest *request, nsresult aStatus)
  720. {
  721. #if defined(DEBUG)
  722. nsAutoCString buffer;
  723. GetURIStringFromRequest(request, buffer);
  724. MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
  725. ("DocLoader:%p: ++ Firing OnStateChange for end url load (...)."
  726. "\tURI: %s status=%x\n",
  727. this, buffer.get(), aStatus));
  728. #endif /* DEBUG */
  729. FireOnStateChange(this,
  730. request,
  731. nsIWebProgressListener::STATE_STOP |
  732. nsIWebProgressListener::STATE_IS_REQUEST,
  733. aStatus);
  734. // Fire a status change message for the most recent unfinished
  735. // request to make sure that the displayed status is not outdated.
  736. if (!mStatusInfoList.isEmpty()) {
  737. nsStatusInfo* statusInfo = mStatusInfoList.getFirst();
  738. FireOnStatusChange(this, statusInfo->mRequest,
  739. statusInfo->mStatusCode,
  740. statusInfo->mStatusMessage.get());
  741. }
  742. }
  743. void nsDocLoader::doStopDocumentLoad(nsIRequest *request,
  744. nsresult aStatus)
  745. {
  746. #if defined(DEBUG)
  747. nsAutoCString buffer;
  748. GetURIStringFromRequest(request, buffer);
  749. MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
  750. ("DocLoader:%p: ++ Firing OnStateChange for end document load (...)."
  751. "\tURI: %s Status=%x\n",
  752. this, buffer.get(), aStatus));
  753. #endif /* DEBUG */
  754. // Firing STATE_STOP|STATE_IS_DOCUMENT will fire onload handlers.
  755. // Grab our parent chain before doing that so we can still dispatch
  756. // STATE_STOP|STATE_IS_WINDW_STATE_IS_NETWORK to them all, even if
  757. // the onload handlers rearrange the docshell tree.
  758. WebProgressList list;
  759. GatherAncestorWebProgresses(list);
  760. //
  761. // Fire an OnStateChange(...) notification indicating the the
  762. // current document has finished loading...
  763. //
  764. int32_t flags = nsIWebProgressListener::STATE_STOP |
  765. nsIWebProgressListener::STATE_IS_DOCUMENT;
  766. for (uint32_t i = 0; i < list.Length(); ++i) {
  767. list[i]->DoFireOnStateChange(this, request, flags, aStatus);
  768. }
  769. //
  770. // Fire a final OnStateChange(...) notification indicating the the
  771. // current document has finished loading...
  772. //
  773. flags = nsIWebProgressListener::STATE_STOP |
  774. nsIWebProgressListener::STATE_IS_WINDOW |
  775. nsIWebProgressListener::STATE_IS_NETWORK;
  776. for (uint32_t i = 0; i < list.Length(); ++i) {
  777. list[i]->DoFireOnStateChange(this, request, flags, aStatus);
  778. }
  779. }
  780. ////////////////////////////////////////////////////////////////////////////////////
  781. // The following section contains support for nsIWebProgress and related stuff
  782. ////////////////////////////////////////////////////////////////////////////////////
  783. NS_IMETHODIMP
  784. nsDocLoader::AddProgressListener(nsIWebProgressListener *aListener,
  785. uint32_t aNotifyMask)
  786. {
  787. if (mListenerInfoList.Contains(aListener)) {
  788. // The listener is already registered!
  789. return NS_ERROR_FAILURE;
  790. }
  791. nsWeakPtr listener = do_GetWeakReference(aListener);
  792. if (!listener) {
  793. return NS_ERROR_INVALID_ARG;
  794. }
  795. return mListenerInfoList.AppendElement(nsListenerInfo(listener, aNotifyMask)) ?
  796. NS_OK : NS_ERROR_OUT_OF_MEMORY;
  797. }
  798. NS_IMETHODIMP
  799. nsDocLoader::RemoveProgressListener(nsIWebProgressListener *aListener)
  800. {
  801. return mListenerInfoList.RemoveElement(aListener) ? NS_OK : NS_ERROR_FAILURE;
  802. }
  803. NS_IMETHODIMP
  804. nsDocLoader::GetDOMWindow(mozIDOMWindowProxy **aResult)
  805. {
  806. return CallGetInterface(this, aResult);
  807. }
  808. NS_IMETHODIMP
  809. nsDocLoader::GetDOMWindowID(uint64_t *aResult)
  810. {
  811. *aResult = 0;
  812. nsCOMPtr<mozIDOMWindowProxy> window;
  813. nsresult rv = GetDOMWindow(getter_AddRefs(window));
  814. NS_ENSURE_SUCCESS(rv, rv);
  815. nsCOMPtr<nsPIDOMWindowOuter> piwindow = nsPIDOMWindowOuter::From(window);
  816. NS_ENSURE_STATE(piwindow);
  817. MOZ_ASSERT(piwindow->IsOuterWindow());
  818. *aResult = piwindow->WindowID();
  819. return NS_OK;
  820. }
  821. NS_IMETHODIMP
  822. nsDocLoader::GetIsTopLevel(bool *aResult)
  823. {
  824. *aResult = false;
  825. nsCOMPtr<mozIDOMWindowProxy> window;
  826. GetDOMWindow(getter_AddRefs(window));
  827. if (window) {
  828. nsCOMPtr<nsPIDOMWindowOuter> piwindow = nsPIDOMWindowOuter::From(window);
  829. NS_ENSURE_STATE(piwindow);
  830. nsCOMPtr<nsPIDOMWindowOuter> topWindow = piwindow->GetTop();
  831. *aResult = piwindow == topWindow;
  832. }
  833. return NS_OK;
  834. }
  835. NS_IMETHODIMP
  836. nsDocLoader::GetIsLoadingDocument(bool *aIsLoadingDocument)
  837. {
  838. *aIsLoadingDocument = mIsLoadingDocument;
  839. return NS_OK;
  840. }
  841. NS_IMETHODIMP
  842. nsDocLoader::GetLoadType(uint32_t *aLoadType)
  843. {
  844. *aLoadType = 0;
  845. return NS_ERROR_NOT_IMPLEMENTED;
  846. }
  847. int64_t nsDocLoader::GetMaxTotalProgress()
  848. {
  849. int64_t newMaxTotal = 0;
  850. uint32_t count = mChildList.Length();
  851. for (uint32_t i=0; i < count; i++)
  852. {
  853. int64_t individualProgress = 0;
  854. nsIDocumentLoader* docloader = ChildAt(i);
  855. if (docloader)
  856. {
  857. // Cast is safe since all children are nsDocLoader too
  858. individualProgress = ((nsDocLoader *) docloader)->GetMaxTotalProgress();
  859. }
  860. if (individualProgress < int64_t(0)) // if one of the elements doesn't know it's size
  861. // then none of them do
  862. {
  863. newMaxTotal = int64_t(-1);
  864. break;
  865. }
  866. else
  867. newMaxTotal += individualProgress;
  868. }
  869. int64_t progress = -1;
  870. if (mMaxSelfProgress >= int64_t(0) && newMaxTotal >= int64_t(0))
  871. progress = newMaxTotal + mMaxSelfProgress;
  872. return progress;
  873. }
  874. ////////////////////////////////////////////////////////////////////////////////////
  875. // The following section contains support for nsIProgressEventSink which is used to
  876. // pass progress and status between the actual request and the doc loader. The doc loader
  877. // then turns around and makes the right web progress calls based on this information.
  878. ////////////////////////////////////////////////////////////////////////////////////
  879. NS_IMETHODIMP nsDocLoader::OnProgress(nsIRequest *aRequest, nsISupports* ctxt,
  880. int64_t aProgress, int64_t aProgressMax)
  881. {
  882. int64_t progressDelta = 0;
  883. //
  884. // Update the RequestInfo entry with the new progress data
  885. //
  886. if (nsRequestInfo* info = GetRequestInfo(aRequest)) {
  887. // Update info->mCurrentProgress before we call FireOnStateChange,
  888. // since that can make the "info" pointer invalid.
  889. int64_t oldCurrentProgress = info->mCurrentProgress;
  890. progressDelta = aProgress - oldCurrentProgress;
  891. info->mCurrentProgress = aProgress;
  892. // suppress sending STATE_TRANSFERRING if this is upload progress (see bug 240053)
  893. if (!info->mUploading && (int64_t(0) == oldCurrentProgress) && (int64_t(0) == info->mMaxProgress)) {
  894. //
  895. // If we receive an OnProgress event from a toplevel channel that the URI Loader
  896. // has not yet targeted, then we must suppress the event. This is necessary to
  897. // ensure that webprogresslisteners do not get confused when the channel is
  898. // finally targeted. See bug 257308.
  899. //
  900. nsLoadFlags lf = 0;
  901. aRequest->GetLoadFlags(&lf);
  902. if ((lf & nsIChannel::LOAD_DOCUMENT_URI) && !(lf & nsIChannel::LOAD_TARGETED)) {
  903. MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
  904. ("DocLoader:%p Ignoring OnProgress while load is not targeted\n", this));
  905. return NS_OK;
  906. }
  907. //
  908. // This is the first progress notification for the entry. If
  909. // (aMaxProgress != -1) then the content-length of the data is known,
  910. // so update mMaxSelfProgress... Otherwise, set it to -1 to indicate
  911. // that the content-length is no longer known.
  912. //
  913. if (aProgressMax != -1) {
  914. mMaxSelfProgress += aProgressMax;
  915. info->mMaxProgress = aProgressMax;
  916. } else {
  917. mMaxSelfProgress = int64_t(-1);
  918. info->mMaxProgress = int64_t(-1);
  919. }
  920. // Send a STATE_TRANSFERRING notification for the request.
  921. int32_t flags;
  922. flags = nsIWebProgressListener::STATE_TRANSFERRING |
  923. nsIWebProgressListener::STATE_IS_REQUEST;
  924. //
  925. // Move the WebProgress into the STATE_TRANSFERRING state if necessary...
  926. //
  927. if (mProgressStateFlags & nsIWebProgressListener::STATE_START) {
  928. mProgressStateFlags = nsIWebProgressListener::STATE_TRANSFERRING;
  929. // Send STATE_TRANSFERRING for the document too...
  930. flags |= nsIWebProgressListener::STATE_IS_DOCUMENT;
  931. }
  932. FireOnStateChange(this, aRequest, flags, NS_OK);
  933. }
  934. // Update our overall current progress count.
  935. mCurrentSelfProgress += progressDelta;
  936. }
  937. //
  938. // The request is not part of the load group, so ignore its progress
  939. // information...
  940. //
  941. else {
  942. #if defined(DEBUG)
  943. nsAutoCString buffer;
  944. GetURIStringFromRequest(aRequest, buffer);
  945. MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
  946. ("DocLoader:%p OOPS - No Request Info for: %s\n",
  947. this, buffer.get()));
  948. #endif /* DEBUG */
  949. return NS_OK;
  950. }
  951. //
  952. // Fire progress notifications out to any registered nsIWebProgressListeners
  953. //
  954. FireOnProgressChange(this, aRequest, aProgress, aProgressMax, progressDelta,
  955. mCurrentTotalProgress, mMaxTotalProgress);
  956. return NS_OK;
  957. }
  958. NS_IMETHODIMP nsDocLoader::OnStatus(nsIRequest* aRequest, nsISupports* ctxt,
  959. nsresult aStatus, const char16_t* aStatusArg)
  960. {
  961. //
  962. // Fire progress notifications out to any registered nsIWebProgressListeners
  963. //
  964. if (aStatus != NS_OK) {
  965. // Remember the current status for this request
  966. nsRequestInfo *info;
  967. info = GetRequestInfo(aRequest);
  968. if (info) {
  969. bool uploading = (aStatus == NS_NET_STATUS_WRITING ||
  970. aStatus == NS_NET_STATUS_SENDING_TO);
  971. // If switching from uploading to downloading (or vice versa), then we
  972. // need to reset our progress counts. This is designed with HTTP form
  973. // submission in mind, where an upload is performed followed by download
  974. // of possibly several documents.
  975. if (info->mUploading != uploading) {
  976. mCurrentSelfProgress = mMaxSelfProgress = 0;
  977. mCurrentTotalProgress = mMaxTotalProgress = 0;
  978. mCompletedTotalProgress = 0;
  979. info->mUploading = uploading;
  980. info->mCurrentProgress = 0;
  981. info->mMaxProgress = 0;
  982. }
  983. }
  984. nsCOMPtr<nsIStringBundleService> sbs =
  985. mozilla::services::GetStringBundleService();
  986. if (!sbs)
  987. return NS_ERROR_FAILURE;
  988. nsXPIDLString msg;
  989. nsresult rv = sbs->FormatStatusMessage(aStatus, aStatusArg,
  990. getter_Copies(msg));
  991. if (NS_FAILED(rv))
  992. return rv;
  993. // Keep around the message. In case a request finishes, we need to make sure
  994. // to send the status message of another request to our user to that we
  995. // don't display, for example, "Transferring" messages for requests that are
  996. // already done.
  997. if (info) {
  998. if (!info->mLastStatus) {
  999. info->mLastStatus = new nsStatusInfo(aRequest);
  1000. } else {
  1001. // We're going to move it to the front of the list, so remove
  1002. // it from wherever it is now.
  1003. info->mLastStatus->remove();
  1004. }
  1005. info->mLastStatus->mStatusMessage = msg;
  1006. info->mLastStatus->mStatusCode = aStatus;
  1007. // Put the info at the front of the list
  1008. mStatusInfoList.insertFront(info->mLastStatus);
  1009. }
  1010. FireOnStatusChange(this, aRequest, aStatus, msg);
  1011. }
  1012. return NS_OK;
  1013. }
  1014. void nsDocLoader::ClearInternalProgress()
  1015. {
  1016. ClearRequestInfoHash();
  1017. mCurrentSelfProgress = mMaxSelfProgress = 0;
  1018. mCurrentTotalProgress = mMaxTotalProgress = 0;
  1019. mCompletedTotalProgress = 0;
  1020. mProgressStateFlags = nsIWebProgressListener::STATE_STOP;
  1021. }
  1022. /**
  1023. * |_code| is executed for every listener matching |_flag|
  1024. * |listener| should be used inside |_code| as the nsIWebProgressListener var.
  1025. */
  1026. #define NOTIFY_LISTENERS(_flag, _code) \
  1027. PR_BEGIN_MACRO \
  1028. nsCOMPtr<nsIWebProgressListener> listener; \
  1029. ListenerArray::BackwardIterator iter(mListenerInfoList); \
  1030. while (iter.HasMore()) { \
  1031. nsListenerInfo &info = iter.GetNext(); \
  1032. if (!(info.mNotifyMask & (_flag))) { \
  1033. continue; \
  1034. } \
  1035. listener = do_QueryReferent(info.mWeakListener); \
  1036. if (!listener) { \
  1037. iter.Remove(); \
  1038. continue; \
  1039. } \
  1040. _code \
  1041. } \
  1042. mListenerInfoList.Compact(); \
  1043. PR_END_MACRO
  1044. void nsDocLoader::FireOnProgressChange(nsDocLoader *aLoadInitiator,
  1045. nsIRequest *request,
  1046. int64_t aProgress,
  1047. int64_t aProgressMax,
  1048. int64_t aProgressDelta,
  1049. int64_t aTotalProgress,
  1050. int64_t aMaxTotalProgress)
  1051. {
  1052. if (mIsLoadingDocument) {
  1053. mCurrentTotalProgress += aProgressDelta;
  1054. mMaxTotalProgress = GetMaxTotalProgress();
  1055. aTotalProgress = mCurrentTotalProgress;
  1056. aMaxTotalProgress = mMaxTotalProgress;
  1057. }
  1058. #if defined(DEBUG)
  1059. nsAutoCString buffer;
  1060. GetURIStringFromRequest(request, buffer);
  1061. MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
  1062. ("DocLoader:%p: Progress (%s): curSelf: %d maxSelf: %d curTotal: %d maxTotal %d\n",
  1063. this, buffer.get(), aProgress, aProgressMax, aTotalProgress, aMaxTotalProgress));
  1064. #endif /* DEBUG */
  1065. NOTIFY_LISTENERS(nsIWebProgress::NOTIFY_PROGRESS,
  1066. // XXX truncates 64-bit to 32-bit
  1067. listener->OnProgressChange(aLoadInitiator,request,
  1068. int32_t(aProgress), int32_t(aProgressMax),
  1069. int32_t(aTotalProgress), int32_t(aMaxTotalProgress));
  1070. );
  1071. // Pass the notification up to the parent...
  1072. if (mParent) {
  1073. mParent->FireOnProgressChange(aLoadInitiator, request,
  1074. aProgress, aProgressMax,
  1075. aProgressDelta,
  1076. aTotalProgress, aMaxTotalProgress);
  1077. }
  1078. }
  1079. void nsDocLoader::GatherAncestorWebProgresses(WebProgressList& aList)
  1080. {
  1081. for (nsDocLoader* loader = this; loader; loader = loader->mParent) {
  1082. aList.AppendElement(loader);
  1083. }
  1084. }
  1085. void nsDocLoader::FireOnStateChange(nsIWebProgress *aProgress,
  1086. nsIRequest *aRequest,
  1087. int32_t aStateFlags,
  1088. nsresult aStatus)
  1089. {
  1090. WebProgressList list;
  1091. GatherAncestorWebProgresses(list);
  1092. for (uint32_t i = 0; i < list.Length(); ++i) {
  1093. list[i]->DoFireOnStateChange(aProgress, aRequest, aStateFlags, aStatus);
  1094. }
  1095. }
  1096. void nsDocLoader::DoFireOnStateChange(nsIWebProgress * const aProgress,
  1097. nsIRequest * const aRequest,
  1098. int32_t &aStateFlags,
  1099. const nsresult aStatus)
  1100. {
  1101. //
  1102. // Remove the STATE_IS_NETWORK bit if necessary.
  1103. //
  1104. // The rule is to remove this bit, if the notification has been passed
  1105. // up from a child WebProgress, and the current WebProgress is already
  1106. // active...
  1107. //
  1108. if (mIsLoadingDocument &&
  1109. (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK) &&
  1110. (this != aProgress)) {
  1111. aStateFlags &= ~nsIWebProgressListener::STATE_IS_NETWORK;
  1112. }
  1113. // Add the STATE_RESTORING bit if necessary.
  1114. if (mIsRestoringDocument)
  1115. aStateFlags |= nsIWebProgressListener::STATE_RESTORING;
  1116. #if defined(DEBUG)
  1117. nsAutoCString buffer;
  1118. GetURIStringFromRequest(aRequest, buffer);
  1119. MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
  1120. ("DocLoader:%p: Status (%s): code: %x\n",
  1121. this, buffer.get(), aStateFlags));
  1122. #endif /* DEBUG */
  1123. NS_ASSERTION(aRequest, "Firing OnStateChange(...) notification with a NULL request!");
  1124. NOTIFY_LISTENERS(((aStateFlags >> 16) & nsIWebProgress::NOTIFY_STATE_ALL),
  1125. listener->OnStateChange(aProgress, aRequest, aStateFlags, aStatus);
  1126. );
  1127. }
  1128. void
  1129. nsDocLoader::FireOnLocationChange(nsIWebProgress* aWebProgress,
  1130. nsIRequest* aRequest,
  1131. nsIURI *aUri,
  1132. uint32_t aFlags)
  1133. {
  1134. NOTIFY_LISTENERS(nsIWebProgress::NOTIFY_LOCATION,
  1135. MOZ_LOG(gDocLoaderLog, LogLevel::Debug, ("DocLoader [%p] calling %p->OnLocationChange", this, listener.get()));
  1136. listener->OnLocationChange(aWebProgress, aRequest, aUri, aFlags);
  1137. );
  1138. // Pass the notification up to the parent...
  1139. if (mParent) {
  1140. mParent->FireOnLocationChange(aWebProgress, aRequest, aUri, aFlags);
  1141. }
  1142. }
  1143. void
  1144. nsDocLoader::FireOnStatusChange(nsIWebProgress* aWebProgress,
  1145. nsIRequest* aRequest,
  1146. nsresult aStatus,
  1147. const char16_t* aMessage)
  1148. {
  1149. NOTIFY_LISTENERS(nsIWebProgress::NOTIFY_STATUS,
  1150. listener->OnStatusChange(aWebProgress, aRequest, aStatus, aMessage);
  1151. );
  1152. // Pass the notification up to the parent...
  1153. if (mParent) {
  1154. mParent->FireOnStatusChange(aWebProgress, aRequest, aStatus, aMessage);
  1155. }
  1156. }
  1157. bool
  1158. nsDocLoader::RefreshAttempted(nsIWebProgress* aWebProgress,
  1159. nsIURI *aURI,
  1160. int32_t aDelay,
  1161. bool aSameURI)
  1162. {
  1163. /*
  1164. * Returns true if the refresh may proceed,
  1165. * false if the refresh should be blocked.
  1166. */
  1167. bool allowRefresh = true;
  1168. NOTIFY_LISTENERS(nsIWebProgress::NOTIFY_REFRESH,
  1169. nsCOMPtr<nsIWebProgressListener2> listener2 =
  1170. do_QueryReferent(info.mWeakListener);
  1171. if (!listener2)
  1172. continue;
  1173. bool listenerAllowedRefresh;
  1174. nsresult listenerRV = listener2->OnRefreshAttempted(
  1175. aWebProgress, aURI, aDelay, aSameURI, &listenerAllowedRefresh);
  1176. if (NS_FAILED(listenerRV))
  1177. continue;
  1178. allowRefresh = allowRefresh && listenerAllowedRefresh;
  1179. );
  1180. // Pass the notification up to the parent...
  1181. if (mParent) {
  1182. allowRefresh = allowRefresh &&
  1183. mParent->RefreshAttempted(aWebProgress, aURI, aDelay, aSameURI);
  1184. }
  1185. return allowRefresh;
  1186. }
  1187. nsresult nsDocLoader::AddRequestInfo(nsIRequest *aRequest)
  1188. {
  1189. if (!mRequestInfoHash.Add(aRequest, mozilla::fallible)) {
  1190. return NS_ERROR_OUT_OF_MEMORY;
  1191. }
  1192. return NS_OK;
  1193. }
  1194. void nsDocLoader::RemoveRequestInfo(nsIRequest *aRequest)
  1195. {
  1196. mRequestInfoHash.Remove(aRequest);
  1197. }
  1198. nsDocLoader::nsRequestInfo* nsDocLoader::GetRequestInfo(nsIRequest* aRequest)
  1199. {
  1200. return static_cast<nsRequestInfo*>(mRequestInfoHash.Search(aRequest));
  1201. }
  1202. void nsDocLoader::ClearRequestInfoHash(void)
  1203. {
  1204. mRequestInfoHash.Clear();
  1205. }
  1206. int64_t nsDocLoader::CalculateMaxProgress()
  1207. {
  1208. int64_t max = mCompletedTotalProgress;
  1209. for (auto iter = mRequestInfoHash.Iter(); !iter.Done(); iter.Next()) {
  1210. auto info = static_cast<const nsRequestInfo*>(iter.Get());
  1211. if (info->mMaxProgress < info->mCurrentProgress) {
  1212. return int64_t(-1);
  1213. }
  1214. max += info->mMaxProgress;
  1215. }
  1216. return max;
  1217. }
  1218. NS_IMETHODIMP nsDocLoader::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
  1219. nsIChannel *aNewChannel,
  1220. uint32_t aFlags,
  1221. nsIAsyncVerifyRedirectCallback *cb)
  1222. {
  1223. if (aOldChannel)
  1224. {
  1225. nsLoadFlags loadFlags = 0;
  1226. int32_t stateFlags = nsIWebProgressListener::STATE_REDIRECTING |
  1227. nsIWebProgressListener::STATE_IS_REQUEST;
  1228. aOldChannel->GetLoadFlags(&loadFlags);
  1229. // If the document channel is being redirected, then indicate that the
  1230. // document is being redirected in the notification...
  1231. if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
  1232. {
  1233. stateFlags |= nsIWebProgressListener::STATE_IS_DOCUMENT;
  1234. #if defined(DEBUG)
  1235. nsCOMPtr<nsIRequest> request(do_QueryInterface(aOldChannel));
  1236. NS_ASSERTION(request == mDocumentRequest, "Wrong Document Channel");
  1237. #endif /* DEBUG */
  1238. }
  1239. OnRedirectStateChange(aOldChannel, aNewChannel, aFlags, stateFlags);
  1240. FireOnStateChange(this, aOldChannel, stateFlags, NS_OK);
  1241. }
  1242. cb->OnRedirectVerifyCallback(NS_OK);
  1243. return NS_OK;
  1244. }
  1245. /*
  1246. * Implementation of nsISecurityEventSink method...
  1247. */
  1248. NS_IMETHODIMP nsDocLoader::OnSecurityChange(nsISupports * aContext,
  1249. uint32_t aState)
  1250. {
  1251. //
  1252. // Fire progress notifications out to any registered nsIWebProgressListeners.
  1253. //
  1254. nsCOMPtr<nsIRequest> request = do_QueryInterface(aContext);
  1255. nsIWebProgress* webProgress = static_cast<nsIWebProgress*>(this);
  1256. NOTIFY_LISTENERS(nsIWebProgress::NOTIFY_SECURITY,
  1257. listener->OnSecurityChange(webProgress, request, aState);
  1258. );
  1259. // Pass the notification up to the parent...
  1260. if (mParent) {
  1261. mParent->OnSecurityChange(aContext, aState);
  1262. }
  1263. return NS_OK;
  1264. }
  1265. /*
  1266. * Implementation of nsISupportsPriority methods...
  1267. *
  1268. * The priority of the DocLoader _is_ the priority of its LoadGroup.
  1269. *
  1270. * XXX(darin): Once we start storing loadgroups in loadgroups, this code will
  1271. * go away.
  1272. */
  1273. NS_IMETHODIMP nsDocLoader::GetPriority(int32_t *aPriority)
  1274. {
  1275. nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mLoadGroup);
  1276. if (p)
  1277. return p->GetPriority(aPriority);
  1278. *aPriority = 0;
  1279. return NS_OK;
  1280. }
  1281. NS_IMETHODIMP nsDocLoader::SetPriority(int32_t aPriority)
  1282. {
  1283. MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
  1284. ("DocLoader:%p: SetPriority(%d) called\n", this, aPriority));
  1285. nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mLoadGroup);
  1286. if (p)
  1287. p->SetPriority(aPriority);
  1288. NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mChildList, nsDocLoader,
  1289. SetPriority, (aPriority));
  1290. return NS_OK;
  1291. }
  1292. NS_IMETHODIMP nsDocLoader::AdjustPriority(int32_t aDelta)
  1293. {
  1294. MOZ_LOG(gDocLoaderLog, LogLevel::Debug,
  1295. ("DocLoader:%p: AdjustPriority(%d) called\n", this, aDelta));
  1296. nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mLoadGroup);
  1297. if (p)
  1298. p->AdjustPriority(aDelta);
  1299. NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mChildList, nsDocLoader,
  1300. AdjustPriority, (aDelta));
  1301. return NS_OK;
  1302. }
  1303. #if 0
  1304. void nsDocLoader::DumpChannelInfo()
  1305. {
  1306. nsChannelInfo *info;
  1307. int32_t i, count;
  1308. int32_t current=0, max=0;
  1309. printf("==== DocLoader=%x\n", this);
  1310. count = mChannelInfoList.Count();
  1311. for(i=0; i<count; i++) {
  1312. info = (nsChannelInfo *)mChannelInfoList.ElementAt(i);
  1313. #if defined(DEBUG)
  1314. nsAutoCString buffer;
  1315. nsresult rv = NS_OK;
  1316. if (info->mURI) {
  1317. rv = info->mURI->GetSpec(buffer);
  1318. }
  1319. printf(" [%d] current=%d max=%d [%s]\n", i,
  1320. info->mCurrentProgress,
  1321. info->mMaxProgress, buffer.get());
  1322. #endif /* DEBUG */
  1323. current += info->mCurrentProgress;
  1324. if (max >= 0) {
  1325. if (info->mMaxProgress < info->mCurrentProgress) {
  1326. max = -1;
  1327. } else {
  1328. max += info->mMaxProgress;
  1329. }
  1330. }
  1331. }
  1332. printf("\nCurrent=%d Total=%d\n====\n", current, max);
  1333. }
  1334. #endif /* 0 */