nsDirectoryViewer.cpp 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394
  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. /*
  6. A directory viewer object. Parses "application/http-index-format"
  7. per Lou Montulli's original spec:
  8. http://www.mozilla.org/projects/netlib/dirindexformat.html
  9. One added change is for a description entry, for when the
  10. target does not match the filename
  11. */
  12. #include "nsDirectoryViewer.h"
  13. #include "nsArray.h"
  14. #include "nsArrayUtils.h"
  15. #include "nsIDirIndex.h"
  16. #include "nsIDocShell.h"
  17. #include "jsapi.h"
  18. #include "nsCOMPtr.h"
  19. #include "nsEnumeratorUtils.h"
  20. #include "nsEscape.h"
  21. #include "nsIRDFService.h"
  22. #include "nsRDFCID.h"
  23. #include "rdf.h"
  24. #include "nsIServiceManager.h"
  25. #include "nsIXPConnect.h"
  26. #include "nsEnumeratorUtils.h"
  27. #include "nsString.h"
  28. #include "nsXPIDLString.h"
  29. #include "nsReadableUtils.h"
  30. #include "nsITextToSubURI.h"
  31. #include "nsIInterfaceRequestor.h"
  32. #include "nsIInterfaceRequestorUtils.h"
  33. #include "nsIFTPChannel.h"
  34. #include "nsIWindowWatcher.h"
  35. #include "nsIPrompt.h"
  36. #include "nsIAuthPrompt.h"
  37. #include "nsIProgressEventSink.h"
  38. #include "nsIDOMWindow.h"
  39. #include "nsIDOMElement.h"
  40. #include "nsIStreamConverterService.h"
  41. #include "nsICategoryManager.h"
  42. #include "nsXPCOMCID.h"
  43. #include "nsIDocument.h"
  44. #include "mozilla/Preferences.h"
  45. #include "mozilla/dom/ScriptSettings.h"
  46. #include "nsContentUtils.h"
  47. #include "nsIURI.h"
  48. #include "nsNetUtil.h"
  49. using namespace mozilla;
  50. static const int FORMAT_XUL = 3;
  51. //----------------------------------------------------------------------
  52. //
  53. // Common CIDs
  54. //
  55. static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
  56. // Various protocols we have to special case
  57. static const char kFTPProtocol[] = "ftp://";
  58. //----------------------------------------------------------------------
  59. //
  60. // nsHTTPIndex
  61. //
  62. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsHTTPIndex)
  63. NS_INTERFACE_MAP_ENTRY(nsIHTTPIndex)
  64. NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource)
  65. NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
  66. NS_INTERFACE_MAP_ENTRY(nsIDirIndexListener)
  67. NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
  68. NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
  69. NS_INTERFACE_MAP_ENTRY(nsIFTPEventSink)
  70. NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIHTTPIndex)
  71. NS_INTERFACE_MAP_END
  72. NS_IMPL_CYCLE_COLLECTION(nsHTTPIndex, mInner)
  73. NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHTTPIndex)
  74. NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHTTPIndex)
  75. NS_IMETHODIMP
  76. nsHTTPIndex::GetInterface(const nsIID &anIID, void **aResult )
  77. {
  78. if (anIID.Equals(NS_GET_IID(nsIFTPEventSink))) {
  79. // If we don't have a container to store the logged data
  80. // then don't report ourselves back to the caller
  81. if (!mRequestor)
  82. return NS_ERROR_NO_INTERFACE;
  83. *aResult = static_cast<nsIFTPEventSink*>(this);
  84. NS_ADDREF(this);
  85. return NS_OK;
  86. }
  87. if (anIID.Equals(NS_GET_IID(nsIPrompt))) {
  88. if (!mRequestor)
  89. return NS_ERROR_NO_INTERFACE;
  90. nsCOMPtr<nsPIDOMWindowOuter> aDOMWindow = do_GetInterface(mRequestor);
  91. if (!aDOMWindow)
  92. return NS_ERROR_NO_INTERFACE;
  93. nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
  94. return wwatch->GetNewPrompter(aDOMWindow, (nsIPrompt**)aResult);
  95. }
  96. if (anIID.Equals(NS_GET_IID(nsIAuthPrompt))) {
  97. if (!mRequestor)
  98. return NS_ERROR_NO_INTERFACE;
  99. nsCOMPtr<nsPIDOMWindowOuter> aDOMWindow = do_GetInterface(mRequestor);
  100. if (!aDOMWindow)
  101. return NS_ERROR_NO_INTERFACE;
  102. nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
  103. return wwatch->GetNewAuthPrompter(aDOMWindow, (nsIAuthPrompt**)aResult);
  104. }
  105. if (anIID.Equals(NS_GET_IID(nsIProgressEventSink))) {
  106. if (!mRequestor)
  107. return NS_ERROR_NO_INTERFACE;
  108. nsCOMPtr<nsIProgressEventSink> sink = do_GetInterface(mRequestor);
  109. if (!sink)
  110. return NS_ERROR_NO_INTERFACE;
  111. *aResult = sink;
  112. NS_ADDREF((nsISupports*)*aResult);
  113. return NS_OK;
  114. }
  115. return NS_ERROR_NO_INTERFACE;
  116. }
  117. NS_IMETHODIMP
  118. nsHTTPIndex::OnFTPControlLog(bool server, const char *msg)
  119. {
  120. NS_ENSURE_TRUE(mRequestor, NS_OK);
  121. nsCOMPtr<nsIGlobalObject> globalObject = do_GetInterface(mRequestor);
  122. NS_ENSURE_TRUE(globalObject, NS_OK);
  123. // We're going to run script via JS_CallFunctionName, so we need an
  124. // AutoEntryScript. This is Gecko specific and not in any spec.
  125. dom::AutoEntryScript aes(globalObject,
  126. "nsHTTPIndex OnFTPControlLog");
  127. JSContext* cx = aes.cx();
  128. JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
  129. NS_ENSURE_TRUE(global, NS_OK);
  130. nsString unicodeMsg;
  131. unicodeMsg.AssignWithConversion(msg);
  132. JSString* jsMsgStr = JS_NewUCStringCopyZ(cx, unicodeMsg.get());
  133. NS_ENSURE_TRUE(jsMsgStr, NS_ERROR_OUT_OF_MEMORY);
  134. JS::AutoValueArray<2> params(cx);
  135. params[0].setBoolean(server);
  136. params[1].setString(jsMsgStr);
  137. JS::Rooted<JS::Value> val(cx);
  138. JS_CallFunctionName(cx,
  139. global,
  140. "OnFTPControlLog",
  141. params,
  142. &val);
  143. return NS_OK;
  144. }
  145. NS_IMETHODIMP
  146. nsHTTPIndex::SetEncoding(const char *encoding)
  147. {
  148. mEncoding = encoding;
  149. return(NS_OK);
  150. }
  151. NS_IMETHODIMP
  152. nsHTTPIndex::GetEncoding(char **encoding)
  153. {
  154. NS_PRECONDITION(encoding, "null ptr");
  155. if (! encoding)
  156. return(NS_ERROR_NULL_POINTER);
  157. *encoding = ToNewCString(mEncoding);
  158. if (!*encoding)
  159. return(NS_ERROR_OUT_OF_MEMORY);
  160. return(NS_OK);
  161. }
  162. NS_IMETHODIMP
  163. nsHTTPIndex::OnStartRequest(nsIRequest *request, nsISupports* aContext)
  164. {
  165. nsresult rv;
  166. mParser = do_CreateInstance(NS_DIRINDEXPARSER_CONTRACTID, &rv);
  167. if (NS_FAILED(rv)) return rv;
  168. rv = mParser->SetEncoding(mEncoding.get());
  169. if (NS_FAILED(rv)) return rv;
  170. rv = mParser->SetListener(this);
  171. if (NS_FAILED(rv)) return rv;
  172. rv = mParser->OnStartRequest(request,aContext);
  173. if (NS_FAILED(rv)) return rv;
  174. // This should only run once...
  175. // Unless we don't have a container to start with
  176. // (ie called from bookmarks as an rdf datasource)
  177. if (mBindToGlobalObject && mRequestor) {
  178. mBindToGlobalObject = false;
  179. nsCOMPtr<nsIGlobalObject> globalObject = do_GetInterface(mRequestor);
  180. NS_ENSURE_TRUE(globalObject, NS_ERROR_FAILURE);
  181. // We might run script via JS_SetProperty, so we need an AutoEntryScript.
  182. // This is Gecko specific and not in any spec.
  183. dom::AutoEntryScript aes(globalObject,
  184. "nsHTTPIndex set HTTPIndex property");
  185. JSContext* cx = aes.cx();
  186. JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
  187. // Using XPConnect, wrap the HTTP index object...
  188. static NS_DEFINE_CID(kXPConnectCID, NS_XPCONNECT_CID);
  189. nsCOMPtr<nsIXPConnect> xpc(do_GetService(kXPConnectCID, &rv));
  190. if (NS_FAILED(rv)) return rv;
  191. JS::Rooted<JSObject*> jsobj(cx);
  192. rv = xpc->WrapNative(cx,
  193. global,
  194. static_cast<nsIHTTPIndex*>(this),
  195. NS_GET_IID(nsIHTTPIndex),
  196. jsobj.address());
  197. NS_ASSERTION(NS_SUCCEEDED(rv), "unable to xpconnect-wrap http-index");
  198. if (NS_FAILED(rv)) return rv;
  199. NS_ASSERTION(jsobj,
  200. "unable to get jsobj from xpconnect wrapper");
  201. if (!jsobj) return NS_ERROR_UNEXPECTED;
  202. JS::Rooted<JS::Value> jslistener(cx, JS::ObjectValue(*jsobj));
  203. // ...and stuff it into the global context
  204. bool ok = JS_SetProperty(cx, global, "HTTPIndex", jslistener);
  205. NS_ASSERTION(ok, "unable to set Listener property");
  206. if (!ok)
  207. return NS_ERROR_FAILURE;
  208. }
  209. if (!aContext) {
  210. nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
  211. NS_ASSERTION(channel, "request should be a channel");
  212. // lets hijack the notifications:
  213. channel->SetNotificationCallbacks(this);
  214. // now create the top most resource
  215. nsCOMPtr<nsIURI> uri;
  216. channel->GetURI(getter_AddRefs(uri));
  217. nsAutoCString entryuriC;
  218. rv = uri->GetSpec(entryuriC);
  219. if (NS_FAILED(rv)) return rv;
  220. nsCOMPtr<nsIRDFResource> entry;
  221. rv = mDirRDF->GetResource(entryuriC, getter_AddRefs(entry));
  222. NS_ConvertUTF8toUTF16 uriUnicode(entryuriC);
  223. nsCOMPtr<nsIRDFLiteral> URLVal;
  224. rv = mDirRDF->GetLiteral(uriUnicode.get(), getter_AddRefs(URLVal));
  225. Assert(entry, kNC_URL, URLVal, true);
  226. mDirectory = do_QueryInterface(entry);
  227. }
  228. else
  229. {
  230. // Get the directory from the context
  231. mDirectory = do_QueryInterface(aContext);
  232. }
  233. if (!mDirectory) {
  234. request->Cancel(NS_BINDING_ABORTED);
  235. return NS_BINDING_ABORTED;
  236. }
  237. // Mark the directory as "loading"
  238. rv = Assert(mDirectory, kNC_Loading,
  239. kTrueLiteral, true);
  240. if (NS_FAILED(rv)) return rv;
  241. return NS_OK;
  242. }
  243. NS_IMETHODIMP
  244. nsHTTPIndex::OnStopRequest(nsIRequest *request,
  245. nsISupports* aContext,
  246. nsresult aStatus)
  247. {
  248. // If mDirectory isn't set, then we should just bail. Either an
  249. // error occurred and OnStartRequest() never got called, or
  250. // something exploded in OnStartRequest().
  251. if (! mDirectory)
  252. return NS_BINDING_ABORTED;
  253. mParser->OnStopRequest(request,aContext,aStatus);
  254. nsresult rv;
  255. nsXPIDLCString commentStr;
  256. mParser->GetComment(getter_Copies(commentStr));
  257. nsCOMPtr<nsIRDFLiteral> comment;
  258. rv = mDirRDF->GetLiteral(NS_ConvertASCIItoUTF16(commentStr).get(), getter_AddRefs(comment));
  259. if (NS_FAILED(rv)) return rv;
  260. rv = Assert(mDirectory, kNC_Comment, comment, true);
  261. if (NS_FAILED(rv)) return rv;
  262. // hack: Remove the 'loading' annotation (ignore errors)
  263. AddElement(mDirectory, kNC_Loading, kTrueLiteral);
  264. return NS_OK;
  265. }
  266. NS_IMETHODIMP
  267. nsHTTPIndex::OnDataAvailable(nsIRequest *request,
  268. nsISupports* aContext,
  269. nsIInputStream* aStream,
  270. uint64_t aSourceOffset,
  271. uint32_t aCount)
  272. {
  273. // If mDirectory isn't set, then we should just bail. Either an
  274. // error occurred and OnStartRequest() never got called, or
  275. // something exploded in OnStartRequest().
  276. if (! mDirectory)
  277. return NS_BINDING_ABORTED;
  278. return mParser->OnDataAvailable(request, mDirectory, aStream, aSourceOffset, aCount);
  279. }
  280. nsresult
  281. nsHTTPIndex::OnIndexAvailable(nsIRequest* aRequest, nsISupports *aContext,
  282. nsIDirIndex* aIndex)
  283. {
  284. nsCOMPtr<nsIRDFResource> parentRes = do_QueryInterface(aContext);
  285. if (!parentRes) {
  286. NS_ERROR("Could not obtain parent resource");
  287. return(NS_ERROR_UNEXPECTED);
  288. }
  289. const char* baseStr;
  290. parentRes->GetValueConst(&baseStr);
  291. if (! baseStr) {
  292. NS_ERROR("Could not reconstruct base uri");
  293. return NS_ERROR_UNEXPECTED;
  294. }
  295. // we found the filename; construct a resource for its entry
  296. nsAutoCString entryuriC(baseStr);
  297. nsXPIDLCString filename;
  298. nsresult rv = aIndex->GetLocation(getter_Copies(filename));
  299. if (NS_FAILED(rv)) return rv;
  300. entryuriC.Append(filename);
  301. // if its a directory, make sure it ends with a trailing slash.
  302. uint32_t type;
  303. rv = aIndex->GetType(&type);
  304. if (NS_FAILED(rv))
  305. return rv;
  306. bool isDirType = (type == nsIDirIndex::TYPE_DIRECTORY);
  307. if (isDirType && entryuriC.Last() != '/') {
  308. entryuriC.Append('/');
  309. }
  310. nsCOMPtr<nsIRDFResource> entry;
  311. rv = mDirRDF->GetResource(entryuriC, getter_AddRefs(entry));
  312. // At this point, we'll (hopefully) have found the filename and
  313. // constructed a resource for it, stored in entry. So now take a
  314. // second pass through the values and add as statements to the RDF
  315. // datasource.
  316. if (entry && NS_SUCCEEDED(rv)) {
  317. nsCOMPtr<nsIRDFLiteral> lit;
  318. nsString str;
  319. str.AssignWithConversion(entryuriC.get());
  320. rv = mDirRDF->GetLiteral(str.get(), getter_AddRefs(lit));
  321. if (NS_SUCCEEDED(rv)) {
  322. rv = Assert(entry, kNC_URL, lit, true);
  323. if (NS_FAILED(rv)) return rv;
  324. nsXPIDLString xpstr;
  325. // description
  326. rv = aIndex->GetDescription(getter_Copies(xpstr));
  327. if (NS_FAILED(rv)) return rv;
  328. if (xpstr.Last() == '/')
  329. xpstr.Truncate(xpstr.Length() - 1);
  330. rv = mDirRDF->GetLiteral(xpstr.get(), getter_AddRefs(lit));
  331. if (NS_FAILED(rv)) return rv;
  332. rv = Assert(entry, kNC_Description, lit, true);
  333. if (NS_FAILED(rv)) return rv;
  334. // contentlength
  335. int64_t size;
  336. rv = aIndex->GetSize(&size);
  337. if (NS_FAILED(rv)) return rv;
  338. int64_t minus1 = UINT64_MAX;
  339. if (size != minus1) {
  340. int32_t intSize = int32_t(size);
  341. // XXX RDF should support 64 bit integers (bug 240160)
  342. nsCOMPtr<nsIRDFInt> val;
  343. rv = mDirRDF->GetIntLiteral(intSize, getter_AddRefs(val));
  344. if (NS_FAILED(rv)) return rv;
  345. rv = Assert(entry, kNC_ContentLength, val, true);
  346. if (NS_FAILED(rv)) return rv;
  347. }
  348. // lastmodified
  349. PRTime tm;
  350. rv = aIndex->GetLastModified(&tm);
  351. if (NS_FAILED(rv)) return rv;
  352. if (tm != -1) {
  353. nsCOMPtr<nsIRDFDate> val;
  354. rv = mDirRDF->GetDateLiteral(tm, getter_AddRefs(val));
  355. if (NS_FAILED(rv)) return rv;
  356. rv = Assert(entry, kNC_LastModified, val, true);
  357. }
  358. // filetype
  359. uint32_t type;
  360. rv = aIndex->GetType(&type);
  361. switch (type) {
  362. case nsIDirIndex::TYPE_UNKNOWN:
  363. rv = mDirRDF->GetLiteral(u"UNKNOWN", getter_AddRefs(lit));
  364. break;
  365. case nsIDirIndex::TYPE_DIRECTORY:
  366. rv = mDirRDF->GetLiteral(u"DIRECTORY", getter_AddRefs(lit));
  367. break;
  368. case nsIDirIndex::TYPE_FILE:
  369. rv = mDirRDF->GetLiteral(u"FILE", getter_AddRefs(lit));
  370. break;
  371. case nsIDirIndex::TYPE_SYMLINK:
  372. rv = mDirRDF->GetLiteral(u"SYMLINK", getter_AddRefs(lit));
  373. break;
  374. }
  375. if (NS_FAILED(rv)) return rv;
  376. rv = Assert(entry, kNC_FileType, lit, true);
  377. if (NS_FAILED(rv)) return rv;
  378. }
  379. // Since the definition of a directory depends on the protocol, we would have
  380. // to do string comparisons all the time.
  381. // But we're told if we're a container right here - so save that fact
  382. if (isDirType)
  383. Assert(entry, kNC_IsContainer, kTrueLiteral, true);
  384. else
  385. Assert(entry, kNC_IsContainer, kFalseLiteral, true);
  386. // instead of
  387. // rv = Assert(parentRes, kNC_Child, entry, true);
  388. // if (NS_FAILED(rv)) return rv;
  389. // defer insertion onto a timer so that the UI isn't starved
  390. AddElement(parentRes, kNC_Child, entry);
  391. }
  392. return rv;
  393. }
  394. nsresult
  395. nsHTTPIndex::OnInformationAvailable(nsIRequest *aRequest,
  396. nsISupports *aCtxt,
  397. const nsAString& aInfo) {
  398. return NS_ERROR_NOT_IMPLEMENTED;
  399. }
  400. //----------------------------------------------------------------------
  401. //
  402. // nsHTTPIndex implementation
  403. //
  404. nsHTTPIndex::nsHTTPIndex()
  405. : mBindToGlobalObject(true),
  406. mRequestor(nullptr)
  407. {
  408. }
  409. nsHTTPIndex::nsHTTPIndex(nsIInterfaceRequestor* aRequestor)
  410. : mBindToGlobalObject(true),
  411. mRequestor(aRequestor)
  412. {
  413. }
  414. nsHTTPIndex::~nsHTTPIndex()
  415. {
  416. // note: these are NOT statics due to the native of nsHTTPIndex
  417. // where it may or may not be treated as a singleton
  418. if (mTimer)
  419. {
  420. // be sure to cancel the timer, as it holds a
  421. // weak reference back to nsHTTPIndex
  422. mTimer->Cancel();
  423. mTimer = nullptr;
  424. }
  425. mConnectionList = nullptr;
  426. mNodeList = nullptr;
  427. if (mDirRDF)
  428. {
  429. // UnregisterDataSource() may fail; just ignore errors
  430. mDirRDF->UnregisterDataSource(this);
  431. }
  432. }
  433. nsresult
  434. nsHTTPIndex::CommonInit()
  435. {
  436. nsresult rv = NS_OK;
  437. // set initial/default encoding to ISO-8859-1 (not UTF-8)
  438. mEncoding = "ISO-8859-1";
  439. mDirRDF = do_GetService(kRDFServiceCID, &rv);
  440. NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF service");
  441. if (NS_FAILED(rv)) {
  442. return(rv);
  443. }
  444. mInner = do_CreateInstance("@mozilla.org/rdf/datasource;1?name=in-memory-datasource", &rv);
  445. if (NS_FAILED(rv))
  446. return rv;
  447. mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "child"),
  448. getter_AddRefs(kNC_Child));
  449. mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "loading"),
  450. getter_AddRefs(kNC_Loading));
  451. mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Comment"),
  452. getter_AddRefs(kNC_Comment));
  453. mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "URL"),
  454. getter_AddRefs(kNC_URL));
  455. mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Name"),
  456. getter_AddRefs(kNC_Description));
  457. mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Content-Length"),
  458. getter_AddRefs(kNC_ContentLength));
  459. mDirRDF->GetResource(NS_LITERAL_CSTRING(WEB_NAMESPACE_URI "LastModifiedDate"),
  460. getter_AddRefs(kNC_LastModified));
  461. mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Content-Type"),
  462. getter_AddRefs(kNC_ContentType));
  463. mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "File-Type"),
  464. getter_AddRefs(kNC_FileType));
  465. mDirRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "IsContainer"),
  466. getter_AddRefs(kNC_IsContainer));
  467. rv = mDirRDF->GetLiteral(u"true", getter_AddRefs(kTrueLiteral));
  468. if (NS_FAILED(rv)) return(rv);
  469. rv = mDirRDF->GetLiteral(u"false", getter_AddRefs(kFalseLiteral));
  470. if (NS_FAILED(rv)) return(rv);
  471. mConnectionList = nsArray::Create();
  472. // note: don't register DS here
  473. return rv;
  474. }
  475. nsresult
  476. nsHTTPIndex::Init()
  477. {
  478. nsresult rv;
  479. // set initial/default encoding to ISO-8859-1 (not UTF-8)
  480. mEncoding = "ISO-8859-1";
  481. rv = CommonInit();
  482. if (NS_FAILED(rv)) return(rv);
  483. // (do this last) register this as a named data source with the RDF service
  484. rv = mDirRDF->RegisterDataSource(this, false);
  485. if (NS_FAILED(rv)) return(rv);
  486. return(NS_OK);
  487. }
  488. nsresult
  489. nsHTTPIndex::Init(nsIURI* aBaseURL)
  490. {
  491. NS_PRECONDITION(aBaseURL != nullptr, "null ptr");
  492. if (! aBaseURL)
  493. return NS_ERROR_NULL_POINTER;
  494. nsresult rv;
  495. rv = CommonInit();
  496. if (NS_FAILED(rv)) return(rv);
  497. // note: don't register DS here (singleton case)
  498. rv = aBaseURL->GetSpec(mBaseURL);
  499. if (NS_FAILED(rv)) return rv;
  500. // Mark the base url as a container
  501. nsCOMPtr<nsIRDFResource> baseRes;
  502. mDirRDF->GetResource(mBaseURL, getter_AddRefs(baseRes));
  503. Assert(baseRes, kNC_IsContainer, kTrueLiteral, true);
  504. return NS_OK;
  505. }
  506. nsresult
  507. nsHTTPIndex::Create(nsIURI* aBaseURL, nsIInterfaceRequestor* aRequestor,
  508. nsIHTTPIndex** aResult)
  509. {
  510. *aResult = nullptr;
  511. nsHTTPIndex* result = new nsHTTPIndex(aRequestor);
  512. nsresult rv = result->Init(aBaseURL);
  513. if (NS_SUCCEEDED(rv))
  514. {
  515. NS_ADDREF(result);
  516. *aResult = result;
  517. }
  518. else
  519. {
  520. delete result;
  521. }
  522. return rv;
  523. }
  524. NS_IMETHODIMP
  525. nsHTTPIndex::GetBaseURL(char** _result)
  526. {
  527. *_result = ToNewCString(mBaseURL);
  528. if (! *_result)
  529. return NS_ERROR_OUT_OF_MEMORY;
  530. return NS_OK;
  531. }
  532. NS_IMETHODIMP
  533. nsHTTPIndex::GetDataSource(nsIRDFDataSource** _result)
  534. {
  535. NS_ADDREF(*_result = this);
  536. return NS_OK;
  537. }
  538. // This function finds the destination when following a given nsIRDFResource
  539. // If the resource has a URL attribute, we use that. If not, just use
  540. // the uri.
  541. //
  542. // Do NOT try to get the destination of a uri in any other way
  543. void nsHTTPIndex::GetDestination(nsIRDFResource* r, nsXPIDLCString& dest) {
  544. // First try the URL attribute
  545. nsCOMPtr<nsIRDFNode> node;
  546. GetTarget(r, kNC_URL, true, getter_AddRefs(node));
  547. nsCOMPtr<nsIRDFLiteral> url;
  548. if (node)
  549. url = do_QueryInterface(node);
  550. if (!url) {
  551. const char* temp;
  552. r->GetValueConst(&temp);
  553. dest.Adopt(temp ? strdup(temp) : 0);
  554. } else {
  555. const char16_t* uri;
  556. url->GetValueConst(&uri);
  557. dest.Adopt(ToNewUTF8String(nsDependentString(uri)));
  558. }
  559. }
  560. // rjc: isWellknownContainerURI() decides whether a URI is a container for which,
  561. // when asked (say, by the template builder), we'll make a network connection
  562. // to get its contents. For the moment, all we speak is ftp:// URLs, even though
  563. // a) we can get "http-index" mimetypes for really anything
  564. // b) we could easily handle file:// URLs here
  565. // Q: Why don't we?
  566. // A: The file system datasource ("rdf:file"); at some point, the two
  567. // should be perhaps united. Until then, we can't aggregate both
  568. // "rdf:file" and "http-index" (such as with bookmarks) because we'd
  569. // get double the # of answers we really want... also, "rdf:file" is
  570. // less expensive in terms of both memory usage as well as speed
  571. // We use an rdf attribute to mark if this is a container or not.
  572. // Note that we still have to do string comparisons as a fallback
  573. // because stuff like the personal toolbar and bookmarks check whether
  574. // a URL is a container, and we have no attribute in that case.
  575. bool
  576. nsHTTPIndex::isWellknownContainerURI(nsIRDFResource *r)
  577. {
  578. nsCOMPtr<nsIRDFNode> node;
  579. GetTarget(r, kNC_IsContainer, true, getter_AddRefs(node));
  580. if (node) {
  581. bool isContainerFlag;
  582. if (NS_SUCCEEDED(node->EqualsNode(kTrueLiteral, &isContainerFlag)))
  583. return isContainerFlag;
  584. }
  585. nsXPIDLCString uri;
  586. GetDestination(r, uri);
  587. return uri.get() && !strncmp(uri, kFTPProtocol, sizeof(kFTPProtocol) - 1) &&
  588. (uri.Last() == '/');
  589. }
  590. NS_IMETHODIMP
  591. nsHTTPIndex::GetURI(char * *uri)
  592. {
  593. NS_PRECONDITION(uri != nullptr, "null ptr");
  594. if (! uri)
  595. return(NS_ERROR_NULL_POINTER);
  596. if ((*uri = strdup("rdf:httpindex")) == nullptr)
  597. return(NS_ERROR_OUT_OF_MEMORY);
  598. return(NS_OK);
  599. }
  600. NS_IMETHODIMP
  601. nsHTTPIndex::GetSource(nsIRDFResource *aProperty, nsIRDFNode *aTarget, bool aTruthValue,
  602. nsIRDFResource **_retval)
  603. {
  604. nsresult rv = NS_ERROR_UNEXPECTED;
  605. *_retval = nullptr;
  606. if (mInner)
  607. {
  608. rv = mInner->GetSource(aProperty, aTarget, aTruthValue, _retval);
  609. }
  610. return(rv);
  611. }
  612. NS_IMETHODIMP
  613. nsHTTPIndex::GetSources(nsIRDFResource *aProperty, nsIRDFNode *aTarget, bool aTruthValue,
  614. nsISimpleEnumerator **_retval)
  615. {
  616. nsresult rv = NS_ERROR_UNEXPECTED;
  617. if (mInner)
  618. {
  619. rv = mInner->GetSources(aProperty, aTarget, aTruthValue, _retval);
  620. }
  621. else
  622. {
  623. rv = NS_NewEmptyEnumerator(_retval);
  624. }
  625. return(rv);
  626. }
  627. NS_IMETHODIMP
  628. nsHTTPIndex::GetTarget(nsIRDFResource *aSource, nsIRDFResource *aProperty, bool aTruthValue,
  629. nsIRDFNode **_retval)
  630. {
  631. nsresult rv = NS_ERROR_UNEXPECTED;
  632. *_retval = nullptr;
  633. if ((aTruthValue) && (aProperty == kNC_Child) && isWellknownContainerURI(aSource))
  634. {
  635. // fake out the generic builder (i.e. return anything in this case)
  636. // so that search containers never appear to be empty
  637. NS_IF_ADDREF(aSource);
  638. *_retval = aSource;
  639. return(NS_OK);
  640. }
  641. if (mInner)
  642. {
  643. rv = mInner->GetTarget(aSource, aProperty, aTruthValue, _retval);
  644. }
  645. return(rv);
  646. }
  647. NS_IMETHODIMP
  648. nsHTTPIndex::GetTargets(nsIRDFResource *aSource, nsIRDFResource *aProperty, bool aTruthValue,
  649. nsISimpleEnumerator **_retval)
  650. {
  651. nsresult rv = NS_ERROR_UNEXPECTED;
  652. if (mInner)
  653. {
  654. rv = mInner->GetTargets(aSource, aProperty, aTruthValue, _retval);
  655. }
  656. else
  657. {
  658. rv = NS_NewEmptyEnumerator(_retval);
  659. }
  660. if ((aProperty == kNC_Child) && isWellknownContainerURI(aSource))
  661. {
  662. bool doNetworkRequest = true;
  663. if (NS_SUCCEEDED(rv) && (_retval))
  664. {
  665. // check and see if we already have data for the search in question;
  666. // if we do, don't bother doing the search again
  667. bool hasResults;
  668. if (NS_SUCCEEDED((*_retval)->HasMoreElements(&hasResults)) &&
  669. hasResults)
  670. doNetworkRequest = false;
  671. }
  672. // Note: if we need to do a network request, do it out-of-band
  673. // (because the XUL template builder isn't re-entrant)
  674. // by using a global connection list and an immediately-firing timer
  675. if (doNetworkRequest && mConnectionList)
  676. {
  677. uint32_t connectionIndex;
  678. nsresult idx_rv = mConnectionList->IndexOf(0, aSource, &connectionIndex);
  679. if (NS_FAILED(idx_rv))
  680. {
  681. // add aSource into list of connections to make
  682. mConnectionList->AppendElement(aSource, /*weak =*/ false);
  683. // if we don't have a timer about to fire, create one
  684. // which should fire as soon as possible (out-of-band)
  685. if (!mTimer)
  686. {
  687. mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
  688. NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create a timer");
  689. if (NS_SUCCEEDED(rv))
  690. {
  691. mTimer->InitWithFuncCallback(nsHTTPIndex::FireTimer, this, 1,
  692. nsITimer::TYPE_ONE_SHOT);
  693. // Note: don't addref "this" as we'll cancel the
  694. // timer in the httpIndex destructor
  695. }
  696. }
  697. }
  698. }
  699. }
  700. return(rv);
  701. }
  702. nsresult
  703. nsHTTPIndex::AddElement(nsIRDFResource *parent, nsIRDFResource *prop, nsIRDFNode *child)
  704. {
  705. nsresult rv;
  706. if (!mNodeList)
  707. {
  708. mNodeList = nsArray::Create();
  709. }
  710. // order required: parent, prop, then child
  711. mNodeList->AppendElement(parent, /*weak =*/ false);
  712. mNodeList->AppendElement(prop, /*weak =*/ false);
  713. mNodeList->AppendElement(child, /*weak = */ false);
  714. if (!mTimer)
  715. {
  716. mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
  717. NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create a timer");
  718. if (NS_FAILED(rv)) return(rv);
  719. mTimer->InitWithFuncCallback(nsHTTPIndex::FireTimer, this, 1,
  720. nsITimer::TYPE_ONE_SHOT);
  721. // Note: don't addref "this" as we'll cancel the
  722. // timer in the httpIndex destructor
  723. }
  724. return(NS_OK);
  725. }
  726. void
  727. nsHTTPIndex::FireTimer(nsITimer* aTimer, void* aClosure)
  728. {
  729. nsHTTPIndex *httpIndex = static_cast<nsHTTPIndex *>(aClosure);
  730. if (!httpIndex)
  731. return;
  732. // don't return out of this loop as mTimer may need to be cancelled afterwards
  733. uint32_t numItems = 0;
  734. if (httpIndex->mConnectionList)
  735. {
  736. httpIndex->mConnectionList->GetLength(&numItems);
  737. if (numItems > 0)
  738. {
  739. nsCOMPtr<nsIRDFResource> source =
  740. do_QueryElementAt(httpIndex->mConnectionList, 0);
  741. httpIndex->mConnectionList->RemoveElementAt(0);
  742. nsXPIDLCString uri;
  743. if (source) {
  744. httpIndex->GetDestination(source, uri);
  745. }
  746. if (!uri) {
  747. NS_ERROR("Could not reconstruct uri");
  748. return;
  749. }
  750. nsresult rv = NS_OK;
  751. nsCOMPtr<nsIURI> url;
  752. rv = NS_NewURI(getter_AddRefs(url), uri.get());
  753. nsCOMPtr<nsIChannel> channel;
  754. if (NS_SUCCEEDED(rv) && (url)) {
  755. rv = NS_NewChannel(getter_AddRefs(channel),
  756. url,
  757. nsContentUtils::GetSystemPrincipal(),
  758. nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
  759. nsIContentPolicy::TYPE_OTHER);
  760. }
  761. if (NS_SUCCEEDED(rv) && (channel)) {
  762. channel->SetNotificationCallbacks(httpIndex);
  763. rv = channel->AsyncOpen2(httpIndex);
  764. }
  765. }
  766. }
  767. if (httpIndex->mNodeList)
  768. {
  769. httpIndex->mNodeList->GetLength(&numItems);
  770. if (numItems > 0)
  771. {
  772. // account for order required: src, prop, then target
  773. numItems /=3;
  774. if (numItems > 10)
  775. numItems = 10;
  776. int32_t loop;
  777. for (loop=0; loop<(int32_t)numItems; loop++)
  778. {
  779. nsCOMPtr<nsIRDFResource> src = do_QueryElementAt(httpIndex->mNodeList, 0);
  780. httpIndex->mNodeList->RemoveElementAt(0);
  781. nsCOMPtr<nsIRDFResource> prop = do_QueryElementAt(httpIndex->mNodeList, 0);
  782. httpIndex->mNodeList->RemoveElementAt(0);
  783. nsCOMPtr<nsIRDFNode> target = do_QueryElementAt(httpIndex->mNodeList, 0);
  784. httpIndex->mNodeList->RemoveElementAt(0);
  785. if (src && prop && target)
  786. {
  787. if (prop.get() == httpIndex->kNC_Loading)
  788. {
  789. httpIndex->Unassert(src, prop, target);
  790. }
  791. else
  792. {
  793. httpIndex->Assert(src, prop, target, true);
  794. }
  795. }
  796. }
  797. }
  798. }
  799. bool refireTimer = false;
  800. // check both lists to see if the timer needs to continue firing
  801. if (httpIndex->mConnectionList)
  802. {
  803. httpIndex->mConnectionList->GetLength(&numItems);
  804. if (numItems > 0)
  805. {
  806. refireTimer = true;
  807. }
  808. else
  809. {
  810. httpIndex->mConnectionList->Clear();
  811. }
  812. }
  813. if (httpIndex->mNodeList)
  814. {
  815. httpIndex->mNodeList->GetLength(&numItems);
  816. if (numItems > 0)
  817. {
  818. refireTimer = true;
  819. }
  820. else
  821. {
  822. httpIndex->mNodeList->Clear();
  823. }
  824. }
  825. // be sure to cancel the timer, as it holds a
  826. // weak reference back to nsHTTPIndex
  827. httpIndex->mTimer->Cancel();
  828. httpIndex->mTimer = nullptr;
  829. // after firing off any/all of the connections be sure
  830. // to cancel the timer if we don't need to refire it
  831. if (refireTimer)
  832. {
  833. httpIndex->mTimer = do_CreateInstance("@mozilla.org/timer;1");
  834. if (httpIndex->mTimer)
  835. {
  836. httpIndex->mTimer->InitWithFuncCallback(nsHTTPIndex::FireTimer, aClosure, 10,
  837. nsITimer::TYPE_ONE_SHOT);
  838. // Note: don't addref "this" as we'll cancel the
  839. // timer in the httpIndex destructor
  840. }
  841. }
  842. }
  843. NS_IMETHODIMP
  844. nsHTTPIndex::Assert(nsIRDFResource *aSource, nsIRDFResource *aProperty, nsIRDFNode *aTarget,
  845. bool aTruthValue)
  846. {
  847. nsresult rv = NS_ERROR_UNEXPECTED;
  848. if (mInner)
  849. {
  850. rv = mInner->Assert(aSource, aProperty, aTarget, aTruthValue);
  851. }
  852. return(rv);
  853. }
  854. NS_IMETHODIMP
  855. nsHTTPIndex::Unassert(nsIRDFResource *aSource, nsIRDFResource *aProperty, nsIRDFNode *aTarget)
  856. {
  857. nsresult rv = NS_ERROR_UNEXPECTED;
  858. if (mInner)
  859. {
  860. rv = mInner->Unassert(aSource, aProperty, aTarget);
  861. }
  862. return(rv);
  863. }
  864. NS_IMETHODIMP
  865. nsHTTPIndex::Change(nsIRDFResource *aSource, nsIRDFResource *aProperty,
  866. nsIRDFNode *aOldTarget, nsIRDFNode *aNewTarget)
  867. {
  868. nsresult rv = NS_ERROR_UNEXPECTED;
  869. if (mInner)
  870. {
  871. rv = mInner->Change(aSource, aProperty, aOldTarget, aNewTarget);
  872. }
  873. return(rv);
  874. }
  875. NS_IMETHODIMP
  876. nsHTTPIndex::Move(nsIRDFResource *aOldSource, nsIRDFResource *aNewSource,
  877. nsIRDFResource *aProperty, nsIRDFNode *aTarget)
  878. {
  879. nsresult rv = NS_ERROR_UNEXPECTED;
  880. if (mInner)
  881. {
  882. rv = mInner->Move(aOldSource, aNewSource, aProperty, aTarget);
  883. }
  884. return(rv);
  885. }
  886. NS_IMETHODIMP
  887. nsHTTPIndex::HasAssertion(nsIRDFResource *aSource, nsIRDFResource *aProperty,
  888. nsIRDFNode *aTarget, bool aTruthValue, bool *_retval)
  889. {
  890. nsresult rv = NS_ERROR_UNEXPECTED;
  891. if (mInner)
  892. {
  893. rv = mInner->HasAssertion(aSource, aProperty, aTarget, aTruthValue, _retval);
  894. }
  895. return(rv);
  896. }
  897. NS_IMETHODIMP
  898. nsHTTPIndex::AddObserver(nsIRDFObserver *aObserver)
  899. {
  900. nsresult rv = NS_ERROR_UNEXPECTED;
  901. if (mInner)
  902. {
  903. rv = mInner->AddObserver(aObserver);
  904. }
  905. return(rv);
  906. }
  907. NS_IMETHODIMP
  908. nsHTTPIndex::RemoveObserver(nsIRDFObserver *aObserver)
  909. {
  910. nsresult rv = NS_ERROR_UNEXPECTED;
  911. if (mInner)
  912. {
  913. rv = mInner->RemoveObserver(aObserver);
  914. }
  915. return(rv);
  916. }
  917. NS_IMETHODIMP
  918. nsHTTPIndex::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *result)
  919. {
  920. if (!mInner) {
  921. *result = false;
  922. return NS_OK;
  923. }
  924. return mInner->HasArcIn(aNode, aArc, result);
  925. }
  926. NS_IMETHODIMP
  927. nsHTTPIndex::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *result)
  928. {
  929. if (aArc == kNC_Child && isWellknownContainerURI(aSource)) {
  930. *result = true;
  931. return NS_OK;
  932. }
  933. if (mInner) {
  934. return mInner->HasArcOut(aSource, aArc, result);
  935. }
  936. *result = false;
  937. return NS_OK;
  938. }
  939. NS_IMETHODIMP
  940. nsHTTPIndex::ArcLabelsIn(nsIRDFNode *aNode, nsISimpleEnumerator **_retval)
  941. {
  942. nsresult rv = NS_ERROR_UNEXPECTED;
  943. if (mInner)
  944. {
  945. rv = mInner->ArcLabelsIn(aNode, _retval);
  946. }
  947. return(rv);
  948. }
  949. NS_IMETHODIMP
  950. nsHTTPIndex::ArcLabelsOut(nsIRDFResource *aSource, nsISimpleEnumerator **_retval)
  951. {
  952. *_retval = nullptr;
  953. nsCOMPtr<nsISimpleEnumerator> child, anonArcs;
  954. if (isWellknownContainerURI(aSource))
  955. {
  956. NS_NewSingletonEnumerator(getter_AddRefs(child), kNC_Child);
  957. }
  958. if (mInner)
  959. {
  960. mInner->ArcLabelsOut(aSource, getter_AddRefs(anonArcs));
  961. }
  962. return NS_NewUnionEnumerator(_retval, child, anonArcs);
  963. }
  964. NS_IMETHODIMP
  965. nsHTTPIndex::GetAllResources(nsISimpleEnumerator **_retval)
  966. {
  967. nsresult rv = NS_ERROR_UNEXPECTED;
  968. if (mInner)
  969. {
  970. rv = mInner->GetAllResources(_retval);
  971. }
  972. return(rv);
  973. }
  974. NS_IMETHODIMP
  975. nsHTTPIndex::IsCommandEnabled(nsISupports *aSources, nsIRDFResource *aCommand,
  976. nsISupports *aArguments, bool *_retval)
  977. {
  978. return NS_ERROR_NOT_IMPLEMENTED;
  979. }
  980. NS_IMETHODIMP
  981. nsHTTPIndex::DoCommand(nsISupports *aSources, nsIRDFResource *aCommand,
  982. nsISupports *aArguments)
  983. {
  984. return NS_ERROR_NOT_IMPLEMENTED;
  985. }
  986. NS_IMETHODIMP
  987. nsHTTPIndex::BeginUpdateBatch()
  988. {
  989. return mInner->BeginUpdateBatch();
  990. }
  991. NS_IMETHODIMP
  992. nsHTTPIndex::EndUpdateBatch()
  993. {
  994. return mInner->EndUpdateBatch();
  995. }
  996. NS_IMETHODIMP
  997. nsHTTPIndex::GetAllCmds(nsIRDFResource *aSource, nsISimpleEnumerator **_retval)
  998. {
  999. nsresult rv = NS_ERROR_UNEXPECTED;
  1000. if (mInner)
  1001. {
  1002. rv = mInner->GetAllCmds(aSource, _retval);
  1003. }
  1004. return(rv);
  1005. }
  1006. //----------------------------------------------------------------------
  1007. //
  1008. // nsDirectoryViewerFactory
  1009. //
  1010. nsDirectoryViewerFactory::nsDirectoryViewerFactory()
  1011. {
  1012. }
  1013. nsDirectoryViewerFactory::~nsDirectoryViewerFactory()
  1014. {
  1015. }
  1016. NS_IMPL_ISUPPORTS(nsDirectoryViewerFactory, nsIDocumentLoaderFactory)
  1017. NS_IMETHODIMP
  1018. nsDirectoryViewerFactory::CreateInstance(const char *aCommand,
  1019. nsIChannel* aChannel,
  1020. nsILoadGroup* aLoadGroup,
  1021. const nsACString& aContentType,
  1022. nsIDocShell* aContainer,
  1023. nsISupports* aExtraInfo,
  1024. nsIStreamListener** aDocListenerResult,
  1025. nsIContentViewer** aDocViewerResult)
  1026. {
  1027. nsresult rv;
  1028. bool viewSource = FindInReadable(NS_LITERAL_CSTRING("view-source"),
  1029. aContentType);
  1030. if (!viewSource &&
  1031. Preferences::GetInt("network.dir.format", FORMAT_XUL) == FORMAT_XUL) {
  1032. // ... and setup the original channel's content type
  1033. (void)aChannel->SetContentType(NS_LITERAL_CSTRING("application/vnd.mozilla.xul+xml"));
  1034. // This is where we shunt the HTTP/Index stream into our datasource,
  1035. // and open the directory viewer XUL file as the content stream to
  1036. // load in its place.
  1037. // Create a dummy loader that will load a stub XUL document.
  1038. nsCOMPtr<nsICategoryManager> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv));
  1039. if (NS_FAILED(rv))
  1040. return rv;
  1041. nsXPIDLCString contractID;
  1042. rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", "application/vnd.mozilla.xul+xml",
  1043. getter_Copies(contractID));
  1044. if (NS_FAILED(rv))
  1045. return rv;
  1046. nsCOMPtr<nsIDocumentLoaderFactory> factory(do_GetService(contractID, &rv));
  1047. if (NS_FAILED(rv)) return rv;
  1048. nsCOMPtr<nsIURI> uri;
  1049. rv = NS_NewURI(getter_AddRefs(uri), "chrome://communicator/content/directory/directory.xul");
  1050. if (NS_FAILED(rv)) return rv;
  1051. nsCOMPtr<nsIChannel> channel;
  1052. rv = NS_NewChannel(getter_AddRefs(channel),
  1053. uri,
  1054. nsContentUtils::GetSystemPrincipal(),
  1055. nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
  1056. nsIContentPolicy::TYPE_OTHER,
  1057. aLoadGroup);
  1058. if (NS_FAILED(rv)) return rv;
  1059. nsCOMPtr<nsIStreamListener> listener;
  1060. rv = factory->CreateInstance(aCommand, channel, aLoadGroup,
  1061. NS_LITERAL_CSTRING("application/vnd.mozilla.xul+xml"),
  1062. aContainer, aExtraInfo, getter_AddRefs(listener),
  1063. aDocViewerResult);
  1064. if (NS_FAILED(rv)) return rv;
  1065. rv = channel->AsyncOpen2(listener);
  1066. if (NS_FAILED(rv)) return rv;
  1067. // Create an HTTPIndex object so that we can stuff it into the script context
  1068. nsCOMPtr<nsIURI> baseuri;
  1069. rv = aChannel->GetURI(getter_AddRefs(baseuri));
  1070. if (NS_FAILED(rv)) return rv;
  1071. nsCOMPtr<nsIInterfaceRequestor> requestor = do_QueryInterface(aContainer,&rv);
  1072. if (NS_FAILED(rv)) return rv;
  1073. nsCOMPtr<nsIHTTPIndex> httpindex;
  1074. rv = nsHTTPIndex::Create(baseuri, requestor, getter_AddRefs(httpindex));
  1075. if (NS_FAILED(rv)) return rv;
  1076. // Now shanghai the stream into our http-index parsing datasource
  1077. // wrapper beastie.
  1078. listener = do_QueryInterface(httpindex,&rv);
  1079. *aDocListenerResult = listener.get();
  1080. NS_ADDREF(*aDocListenerResult);
  1081. return NS_OK;
  1082. }
  1083. // setup the original channel's content type
  1084. (void)aChannel->SetContentType(NS_LITERAL_CSTRING("text/html"));
  1085. // Otherwise, lets use the html listing
  1086. nsCOMPtr<nsICategoryManager> catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv));
  1087. if (NS_FAILED(rv))
  1088. return rv;
  1089. nsXPIDLCString contractID;
  1090. rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", "text/html",
  1091. getter_Copies(contractID));
  1092. if (NS_FAILED(rv))
  1093. return rv;
  1094. nsCOMPtr<nsIDocumentLoaderFactory> factory(do_GetService(contractID, &rv));
  1095. if (NS_FAILED(rv)) return rv;
  1096. nsCOMPtr<nsIStreamListener> listener;
  1097. if (viewSource) {
  1098. rv = factory->CreateInstance("view-source", aChannel, aLoadGroup,
  1099. NS_LITERAL_CSTRING("text/html; x-view-type=view-source"),
  1100. aContainer, aExtraInfo, getter_AddRefs(listener),
  1101. aDocViewerResult);
  1102. } else {
  1103. rv = factory->CreateInstance("view", aChannel, aLoadGroup,
  1104. NS_LITERAL_CSTRING("text/html"),
  1105. aContainer, aExtraInfo, getter_AddRefs(listener),
  1106. aDocViewerResult);
  1107. }
  1108. if (NS_FAILED(rv)) return rv;
  1109. nsCOMPtr<nsIStreamConverterService> scs = do_GetService("@mozilla.org/streamConverters;1", &rv);
  1110. if (NS_FAILED(rv)) return rv;
  1111. rv = scs->AsyncConvertData("application/http-index-format",
  1112. "text/html",
  1113. listener,
  1114. nullptr,
  1115. aDocListenerResult);
  1116. if (NS_FAILED(rv)) return rv;
  1117. return NS_OK;
  1118. }
  1119. NS_IMETHODIMP
  1120. nsDirectoryViewerFactory::CreateInstanceForDocument(nsISupports* aContainer,
  1121. nsIDocument* aDocument,
  1122. const char *aCommand,
  1123. nsIContentViewer** aDocViewerResult)
  1124. {
  1125. NS_NOTYETIMPLEMENTED("didn't expect to get here");
  1126. return NS_ERROR_NOT_IMPLEMENTED;
  1127. }
  1128. NS_IMETHODIMP
  1129. nsDirectoryViewerFactory::CreateBlankDocument(nsILoadGroup *aLoadGroup,
  1130. nsIPrincipal *aPrincipal,
  1131. nsIDocument **_retval) {
  1132. NS_NOTYETIMPLEMENTED("didn't expect to get here");
  1133. return NS_ERROR_NOT_IMPLEMENTED;
  1134. }