nsRDFXMLDataSource.cpp 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180
  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  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 data source that can read itself from and write itself to an
  7. RDF/XML stream.
  8. For more information on the RDF/XML syntax,
  9. see http://www.w3.org/TR/REC-rdf-syntax/.
  10. This code is based on the final W3C Recommendation,
  11. http://www.w3.org/TR/1999/REC-rdf-syntax-19990222.
  12. TO DO
  13. -----
  14. 1) Right now, the only kind of stream data sources that are _really_
  15. writable are "file:" URIs. (In fact, _all_ "file:" URIs are
  16. writable, modulo file system permissions; this may lead to some
  17. surprising behavior.) Eventually, it'd be great if we could open
  18. an arbitrary nsIOutputStream on *any* URL, and Netlib could just
  19. do the magic.
  20. 2) Implement a more terse output for "typed" nodes; that is, instead
  21. of "RDF:Description type='ns:foo'", just output "ns:foo".
  22. 3) When re-serializing, we "cheat" for Descriptions that talk about
  23. inline resources (i.e.., using the `ID' attribute specified in
  24. [6.21]). Instead of writing an `ID="foo"' for the first instance,
  25. and then `about="#foo"' for each subsequent instance, we just
  26. _always_ write `about="#foo"'.
  27. We do this so that we can handle the case where an RDF container
  28. has been assigned arbitrary properties: the spec says we can't
  29. dangle the attributes directly off the container, so we need to
  30. refer to it. Of course, with a little cleverness, we could fix
  31. this. But who cares?
  32. 4) When re-serializing containers. We have to cheat on some
  33. containers, and use an illegal "about=" construct. We do this to
  34. handle containers that have been assigned URIs outside of the
  35. local document.
  36. Logging
  37. -------
  38. To turn on logging for this module, set
  39. MOZ_LOG=nsRDFXMLDataSource:5
  40. */
  41. #include "nsIFileStreams.h"
  42. #include "nsIOutputStream.h"
  43. #include "nsIFile.h"
  44. #include "nsIFileChannel.h"
  45. #include "nsIDTD.h"
  46. #include "nsIRDFPurgeableDataSource.h"
  47. #include "nsIInputStream.h"
  48. #include "nsIOutputStream.h"
  49. #include "nsIRDFContainerUtils.h"
  50. #include "nsIRDFNode.h"
  51. #include "nsIRDFRemoteDataSource.h"
  52. #include "nsIRDFService.h"
  53. #include "nsIRDFXMLParser.h"
  54. #include "nsIRDFXMLSerializer.h"
  55. #include "nsIRDFXMLSink.h"
  56. #include "nsIRDFXMLSource.h"
  57. #include "nsISafeOutputStream.h"
  58. #include "nsIServiceManager.h"
  59. #include "nsIStreamListener.h"
  60. #include "nsIURL.h"
  61. #include "nsIFileURL.h"
  62. #include "nsISafeOutputStream.h"
  63. #include "nsIChannel.h"
  64. #include "nsRDFCID.h"
  65. #include "nsRDFBaseDataSources.h"
  66. #include "nsCOMArray.h"
  67. #include "nsXPIDLString.h"
  68. #include "plstr.h"
  69. #include "prio.h"
  70. #include "prthread.h"
  71. #include "rdf.h"
  72. #include "rdfutil.h"
  73. #include "mozilla/Logging.h"
  74. #include "nsNameSpaceMap.h"
  75. #include "nsCRT.h"
  76. #include "nsCycleCollectionParticipant.h"
  77. #include "nsIScriptSecurityManager.h"
  78. #include "nsIChannelEventSink.h"
  79. #include "nsIAsyncVerifyRedirectCallback.h"
  80. #include "nsNetUtil.h"
  81. #include "nsIContentPolicy.h"
  82. #include "nsContentUtils.h"
  83. #include "rdfIDataSource.h"
  84. //----------------------------------------------------------------------
  85. //
  86. // RDFXMLDataSourceImpl
  87. //
  88. class RDFXMLDataSourceImpl : public nsIRDFDataSource,
  89. public nsIRDFRemoteDataSource,
  90. public nsIRDFXMLSink,
  91. public nsIRDFXMLSource,
  92. public nsIStreamListener,
  93. public rdfIDataSource,
  94. public nsIInterfaceRequestor,
  95. public nsIChannelEventSink
  96. {
  97. protected:
  98. enum LoadState {
  99. eLoadState_Unloaded,
  100. eLoadState_Pending,
  101. eLoadState_Loading,
  102. eLoadState_Loaded
  103. };
  104. nsCOMPtr<nsIRDFDataSource> mInner;
  105. bool mIsWritable; // true if the document can be written back
  106. bool mIsDirty; // true if the document should be written back
  107. LoadState mLoadState; // what we're doing now
  108. nsCOMArray<nsIRDFXMLSinkObserver> mObservers;
  109. nsCOMPtr<nsIURI> mURL;
  110. nsCOMPtr<nsIStreamListener> mListener;
  111. nsNameSpaceMap mNameSpaces;
  112. // pseudo-constants
  113. static int32_t gRefCnt;
  114. static nsIRDFService* gRDFService;
  115. static mozilla::LazyLogModule gLog;
  116. nsresult Init();
  117. RDFXMLDataSourceImpl(void);
  118. virtual ~RDFXMLDataSourceImpl(void);
  119. nsresult rdfXMLFlush(nsIURI *aURI);
  120. friend nsresult
  121. NS_NewRDFXMLDataSource(nsIRDFDataSource** aResult);
  122. inline bool IsLoading() {
  123. return (mLoadState == eLoadState_Pending) ||
  124. (mLoadState == eLoadState_Loading);
  125. }
  126. public:
  127. // nsISupports
  128. NS_DECL_CYCLE_COLLECTING_ISUPPORTS
  129. NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(RDFXMLDataSourceImpl,
  130. nsIRDFDataSource)
  131. // nsIRDFDataSource
  132. NS_IMETHOD GetURI(char* *uri) override;
  133. NS_IMETHOD GetSource(nsIRDFResource* property,
  134. nsIRDFNode* target,
  135. bool tv,
  136. nsIRDFResource** source) override {
  137. return mInner->GetSource(property, target, tv, source);
  138. }
  139. NS_IMETHOD GetSources(nsIRDFResource* property,
  140. nsIRDFNode* target,
  141. bool tv,
  142. nsISimpleEnumerator** sources) override {
  143. return mInner->GetSources(property, target, tv, sources);
  144. }
  145. NS_IMETHOD GetTarget(nsIRDFResource* source,
  146. nsIRDFResource* property,
  147. bool tv,
  148. nsIRDFNode** target) override {
  149. return mInner->GetTarget(source, property, tv, target);
  150. }
  151. NS_IMETHOD GetTargets(nsIRDFResource* source,
  152. nsIRDFResource* property,
  153. bool tv,
  154. nsISimpleEnumerator** targets) override {
  155. return mInner->GetTargets(source, property, tv, targets);
  156. }
  157. NS_IMETHOD Assert(nsIRDFResource* aSource,
  158. nsIRDFResource* aProperty,
  159. nsIRDFNode* aTarget,
  160. bool tv) override;
  161. NS_IMETHOD Unassert(nsIRDFResource* source,
  162. nsIRDFResource* property,
  163. nsIRDFNode* target) override;
  164. NS_IMETHOD Change(nsIRDFResource* aSource,
  165. nsIRDFResource* aProperty,
  166. nsIRDFNode* aOldTarget,
  167. nsIRDFNode* aNewTarget) override;
  168. NS_IMETHOD Move(nsIRDFResource* aOldSource,
  169. nsIRDFResource* aNewSource,
  170. nsIRDFResource* aProperty,
  171. nsIRDFNode* aTarget) override;
  172. NS_IMETHOD HasAssertion(nsIRDFResource* source,
  173. nsIRDFResource* property,
  174. nsIRDFNode* target,
  175. bool tv,
  176. bool* hasAssertion) override {
  177. return mInner->HasAssertion(source, property, target, tv, hasAssertion);
  178. }
  179. NS_IMETHOD AddObserver(nsIRDFObserver* aObserver) override {
  180. return mInner->AddObserver(aObserver);
  181. }
  182. NS_IMETHOD RemoveObserver(nsIRDFObserver* aObserver) override {
  183. return mInner->RemoveObserver(aObserver);
  184. }
  185. NS_IMETHOD HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *_retval) override {
  186. return mInner->HasArcIn(aNode, aArc, _retval);
  187. }
  188. NS_IMETHOD HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *_retval) override {
  189. return mInner->HasArcOut(aSource, aArc, _retval);
  190. }
  191. NS_IMETHOD ArcLabelsIn(nsIRDFNode* node,
  192. nsISimpleEnumerator** labels) override {
  193. return mInner->ArcLabelsIn(node, labels);
  194. }
  195. NS_IMETHOD ArcLabelsOut(nsIRDFResource* source,
  196. nsISimpleEnumerator** labels) override {
  197. return mInner->ArcLabelsOut(source, labels);
  198. }
  199. NS_IMETHOD GetAllResources(nsISimpleEnumerator** aResult) override {
  200. return mInner->GetAllResources(aResult);
  201. }
  202. NS_IMETHOD GetAllCmds(nsIRDFResource* source,
  203. nsISimpleEnumerator/*<nsIRDFResource>*/** commands) override {
  204. return mInner->GetAllCmds(source, commands);
  205. }
  206. NS_IMETHOD IsCommandEnabled(nsISupports* aSources,
  207. nsIRDFResource* aCommand,
  208. nsISupports* aArguments,
  209. bool* aResult) override {
  210. return NS_ERROR_NOT_IMPLEMENTED;
  211. }
  212. NS_IMETHOD DoCommand(nsISupports* aSources,
  213. nsIRDFResource* aCommand,
  214. nsISupports* aArguments) override {
  215. return NS_ERROR_NOT_IMPLEMENTED;
  216. }
  217. NS_IMETHOD BeginUpdateBatch() override {
  218. return mInner->BeginUpdateBatch();
  219. }
  220. NS_IMETHOD EndUpdateBatch() override {
  221. return mInner->EndUpdateBatch();
  222. }
  223. // nsIRDFRemoteDataSource interface
  224. NS_DECL_NSIRDFREMOTEDATASOURCE
  225. // nsIRDFXMLSink interface
  226. NS_DECL_NSIRDFXMLSINK
  227. // nsIRDFXMLSource interface
  228. NS_DECL_NSIRDFXMLSOURCE
  229. // nsIRequestObserver
  230. NS_DECL_NSIREQUESTOBSERVER
  231. // nsIStreamListener
  232. NS_DECL_NSISTREAMLISTENER
  233. // nsIInterfaceRequestor
  234. NS_DECL_NSIINTERFACEREQUESTOR
  235. // nsIChannelEventSink
  236. NS_DECL_NSICHANNELEVENTSINK
  237. // rdfIDataSource
  238. NS_IMETHOD VisitAllSubjects(rdfITripleVisitor *aVisitor) override {
  239. nsresult rv;
  240. nsCOMPtr<rdfIDataSource> rdfds = do_QueryInterface(mInner, &rv);
  241. if (NS_FAILED(rv)) return rv;
  242. return rdfds->VisitAllSubjects(aVisitor);
  243. }
  244. NS_IMETHOD VisitAllTriples(rdfITripleVisitor *aVisitor) override {
  245. nsresult rv;
  246. nsCOMPtr<rdfIDataSource> rdfds = do_QueryInterface(mInner, &rv);
  247. if (NS_FAILED(rv)) return rv;
  248. return rdfds->VisitAllTriples(aVisitor);
  249. }
  250. // Implementation methods
  251. bool
  252. MakeQName(nsIRDFResource* aResource,
  253. nsString& property,
  254. nsString& nameSpacePrefix,
  255. nsString& nameSpaceURI);
  256. nsresult
  257. SerializeAssertion(nsIOutputStream* aStream,
  258. nsIRDFResource* aResource,
  259. nsIRDFResource* aProperty,
  260. nsIRDFNode* aValue);
  261. nsresult
  262. SerializeProperty(nsIOutputStream* aStream,
  263. nsIRDFResource* aResource,
  264. nsIRDFResource* aProperty);
  265. bool
  266. IsContainerProperty(nsIRDFResource* aProperty);
  267. nsresult
  268. SerializeDescription(nsIOutputStream* aStream,
  269. nsIRDFResource* aResource);
  270. nsresult
  271. SerializeMember(nsIOutputStream* aStream,
  272. nsIRDFResource* aContainer,
  273. nsIRDFNode* aMember);
  274. nsresult
  275. SerializeContainer(nsIOutputStream* aStream,
  276. nsIRDFResource* aContainer);
  277. nsresult
  278. SerializePrologue(nsIOutputStream* aStream);
  279. nsresult
  280. SerializeEpilogue(nsIOutputStream* aStream);
  281. bool
  282. IsA(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType);
  283. protected:
  284. nsresult
  285. BlockingParse(nsIURI* aURL, nsIStreamListener* aConsumer);
  286. };
  287. int32_t RDFXMLDataSourceImpl::gRefCnt = 0;
  288. nsIRDFService* RDFXMLDataSourceImpl::gRDFService;
  289. mozilla::LazyLogModule RDFXMLDataSourceImpl::gLog("nsRDFXMLDataSource");
  290. static const char kFileURIPrefix[] = "file:";
  291. static const char kResourceURIPrefix[] = "resource:";
  292. //----------------------------------------------------------------------
  293. nsresult
  294. NS_NewRDFXMLDataSource(nsIRDFDataSource** aResult)
  295. {
  296. NS_PRECONDITION(aResult != nullptr, "null ptr");
  297. if (! aResult)
  298. return NS_ERROR_NULL_POINTER;
  299. RDFXMLDataSourceImpl* datasource = new RDFXMLDataSourceImpl();
  300. if (! datasource)
  301. return NS_ERROR_OUT_OF_MEMORY;
  302. nsresult rv;
  303. rv = datasource->Init();
  304. if (NS_FAILED(rv)) {
  305. delete datasource;
  306. return rv;
  307. }
  308. NS_ADDREF(datasource);
  309. *aResult = datasource;
  310. return NS_OK;
  311. }
  312. RDFXMLDataSourceImpl::RDFXMLDataSourceImpl(void)
  313. : mIsWritable(true),
  314. mIsDirty(false),
  315. mLoadState(eLoadState_Unloaded)
  316. {
  317. }
  318. nsresult
  319. RDFXMLDataSourceImpl::Init()
  320. {
  321. nsresult rv;
  322. NS_DEFINE_CID(kRDFInMemoryDataSourceCID, NS_RDFINMEMORYDATASOURCE_CID);
  323. mInner = do_CreateInstance(kRDFInMemoryDataSourceCID, &rv);
  324. if (NS_FAILED(rv)) return rv;
  325. if (gRefCnt++ == 0) {
  326. NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
  327. rv = CallGetService(kRDFServiceCID, &gRDFService);
  328. NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF service");
  329. if (NS_FAILED(rv)) return rv;
  330. }
  331. return NS_OK;
  332. }
  333. RDFXMLDataSourceImpl::~RDFXMLDataSourceImpl(void)
  334. {
  335. // Unregister first so that nobody else tries to get us.
  336. (void) gRDFService->UnregisterDataSource(this);
  337. // Now flush contents
  338. (void) Flush();
  339. // Release RDF/XML sink observers
  340. mObservers.Clear();
  341. if (--gRefCnt == 0)
  342. NS_IF_RELEASE(gRDFService);
  343. }
  344. NS_IMPL_CYCLE_COLLECTION_CLASS(RDFXMLDataSourceImpl)
  345. NS_IMPL_CYCLE_COLLECTION_UNLINK_0(RDFXMLDataSourceImpl)
  346. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(RDFXMLDataSourceImpl)
  347. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInner)
  348. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  349. NS_IMPL_CYCLE_COLLECTING_ADDREF(RDFXMLDataSourceImpl)
  350. NS_IMPL_CYCLE_COLLECTING_RELEASE(RDFXMLDataSourceImpl)
  351. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RDFXMLDataSourceImpl)
  352. NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource)
  353. NS_INTERFACE_MAP_ENTRY(nsIRDFRemoteDataSource)
  354. NS_INTERFACE_MAP_ENTRY(nsIRDFXMLSink)
  355. NS_INTERFACE_MAP_ENTRY(nsIRDFXMLSource)
  356. NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
  357. NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
  358. NS_INTERFACE_MAP_ENTRY(rdfIDataSource)
  359. NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
  360. NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
  361. NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRDFDataSource)
  362. NS_INTERFACE_MAP_END
  363. // nsIInterfaceRequestor
  364. NS_IMETHODIMP
  365. RDFXMLDataSourceImpl::GetInterface(const nsIID& aIID, void** aSink)
  366. {
  367. return QueryInterface(aIID, aSink);
  368. }
  369. nsresult
  370. RDFXMLDataSourceImpl::BlockingParse(nsIURI* aURL, nsIStreamListener* aConsumer)
  371. {
  372. nsresult rv;
  373. // XXX I really hate the way that we're spoon-feeding this stuff
  374. // to the parser: it seems like this is something that netlib
  375. // should be able to do by itself.
  376. nsCOMPtr<nsIChannel> channel;
  377. // Null LoadGroup ?
  378. rv = NS_NewChannel(getter_AddRefs(channel),
  379. aURL,
  380. nsContentUtils::GetSystemPrincipal(),
  381. nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
  382. nsIContentPolicy::TYPE_OTHER);
  383. if (NS_FAILED(rv)) return rv;
  384. nsCOMPtr<nsIInputStream> in;
  385. rv = channel->Open2(getter_AddRefs(in));
  386. // Report success if the file doesn't exist, but propagate other errors.
  387. if (rv == NS_ERROR_FILE_NOT_FOUND) return NS_OK;
  388. if (NS_FAILED(rv)) return rv;
  389. if (! in) {
  390. NS_ERROR("no input stream");
  391. return NS_ERROR_FAILURE;
  392. }
  393. // Wrap the channel's input stream in a buffered stream to ensure that
  394. // ReadSegments is implemented (which OnDataAvailable expects).
  395. nsCOMPtr<nsIInputStream> bufStream;
  396. rv = NS_NewBufferedInputStream(getter_AddRefs(bufStream), in,
  397. 4096 /* buffer size */);
  398. if (NS_FAILED(rv)) return rv;
  399. // Notify load observers
  400. int32_t i;
  401. for (i = mObservers.Count() - 1; i >= 0; --i) {
  402. // Make sure to hold a strong reference to the observer so
  403. // that it doesn't go away in this call if it removes itself
  404. // as an observer
  405. nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
  406. if (obs) {
  407. obs->OnBeginLoad(this);
  408. }
  409. }
  410. rv = aConsumer->OnStartRequest(channel, nullptr);
  411. uint64_t offset = 0;
  412. while (NS_SUCCEEDED(rv)) {
  413. // Skip ODA if the channel is canceled
  414. channel->GetStatus(&rv);
  415. if (NS_FAILED(rv))
  416. break;
  417. uint64_t avail;
  418. if (NS_FAILED(rv = bufStream->Available(&avail)))
  419. break; // error
  420. if (avail == 0)
  421. break; // eof
  422. if (avail > UINT32_MAX)
  423. avail = UINT32_MAX;
  424. rv = aConsumer->OnDataAvailable(channel, nullptr, bufStream, offset, (uint32_t)avail);
  425. if (NS_SUCCEEDED(rv))
  426. offset += avail;
  427. }
  428. if (NS_FAILED(rv))
  429. channel->Cancel(rv);
  430. channel->GetStatus(&rv);
  431. aConsumer->OnStopRequest(channel, nullptr, rv);
  432. // Notify load observers
  433. for (i = mObservers.Count() - 1; i >= 0; --i) {
  434. // Make sure to hold a strong reference to the observer so
  435. // that it doesn't go away in this call if it removes itself
  436. // as an observer
  437. nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
  438. if (obs) {
  439. if (NS_FAILED(rv))
  440. obs->OnError(this, rv, nullptr);
  441. obs->OnEndLoad(this);
  442. }
  443. }
  444. return rv;
  445. }
  446. NS_IMETHODIMP
  447. RDFXMLDataSourceImpl::GetLoaded(bool* _result)
  448. {
  449. *_result = (mLoadState == eLoadState_Loaded);
  450. return NS_OK;
  451. }
  452. NS_IMETHODIMP
  453. RDFXMLDataSourceImpl::Init(const char* uri)
  454. {
  455. NS_PRECONDITION(mInner != nullptr, "not initialized");
  456. if (! mInner)
  457. return NS_ERROR_OUT_OF_MEMORY;
  458. nsresult rv;
  459. rv = NS_NewURI(getter_AddRefs(mURL), nsDependentCString(uri));
  460. if (NS_FAILED(rv)) return rv;
  461. // XXX this is a hack: any "file:" URI is considered writable. All
  462. // others are considered read-only.
  463. if ((PL_strncmp(uri, kFileURIPrefix, sizeof(kFileURIPrefix) - 1) != 0) &&
  464. (PL_strncmp(uri, kResourceURIPrefix, sizeof(kResourceURIPrefix) - 1) != 0)) {
  465. mIsWritable = false;
  466. }
  467. rv = gRDFService->RegisterDataSource(this, false);
  468. if (NS_FAILED(rv)) return rv;
  469. return NS_OK;
  470. }
  471. NS_IMETHODIMP
  472. RDFXMLDataSourceImpl::GetURI(char* *aURI)
  473. {
  474. *aURI = nullptr;
  475. if (!mURL) {
  476. return NS_OK;
  477. }
  478. nsAutoCString spec;
  479. nsresult rv = mURL->GetSpec(spec);
  480. NS_ENSURE_SUCCESS(rv, rv);
  481. *aURI = ToNewCString(spec);
  482. if (!*aURI) {
  483. return NS_ERROR_OUT_OF_MEMORY;
  484. }
  485. return NS_OK;
  486. }
  487. NS_IMETHODIMP
  488. RDFXMLDataSourceImpl::Assert(nsIRDFResource* aSource,
  489. nsIRDFResource* aProperty,
  490. nsIRDFNode* aTarget,
  491. bool aTruthValue)
  492. {
  493. // We don't accept assertions unless we're writable (except in the
  494. // case that we're actually _reading_ the datasource in).
  495. nsresult rv;
  496. if (IsLoading()) {
  497. bool hasAssertion = false;
  498. nsCOMPtr<nsIRDFPurgeableDataSource> gcable = do_QueryInterface(mInner);
  499. if (gcable) {
  500. rv = gcable->Mark(aSource, aProperty, aTarget, aTruthValue, &hasAssertion);
  501. if (NS_FAILED(rv)) return rv;
  502. }
  503. rv = NS_RDF_ASSERTION_ACCEPTED;
  504. if (! hasAssertion) {
  505. rv = mInner->Assert(aSource, aProperty, aTarget, aTruthValue);
  506. if (NS_SUCCEEDED(rv) && gcable) {
  507. // Now mark the new assertion, so it doesn't get
  508. // removed when we sweep. Ignore rv, because we want
  509. // to return what mInner->Assert() gave us.
  510. bool didMark;
  511. (void) gcable->Mark(aSource, aProperty, aTarget, aTruthValue, &didMark);
  512. }
  513. if (NS_FAILED(rv)) return rv;
  514. }
  515. return rv;
  516. }
  517. else if (mIsWritable) {
  518. rv = mInner->Assert(aSource, aProperty, aTarget, aTruthValue);
  519. if (rv == NS_RDF_ASSERTION_ACCEPTED)
  520. mIsDirty = true;
  521. return rv;
  522. }
  523. else {
  524. return NS_RDF_ASSERTION_REJECTED;
  525. }
  526. }
  527. NS_IMETHODIMP
  528. RDFXMLDataSourceImpl::Unassert(nsIRDFResource* source,
  529. nsIRDFResource* property,
  530. nsIRDFNode* target)
  531. {
  532. // We don't accept assertions unless we're writable (except in the
  533. // case that we're actually _reading_ the datasource in).
  534. nsresult rv;
  535. if (IsLoading() || mIsWritable) {
  536. rv = mInner->Unassert(source, property, target);
  537. if (!IsLoading() && rv == NS_RDF_ASSERTION_ACCEPTED)
  538. mIsDirty = true;
  539. }
  540. else {
  541. rv = NS_RDF_ASSERTION_REJECTED;
  542. }
  543. return rv;
  544. }
  545. NS_IMETHODIMP
  546. RDFXMLDataSourceImpl::Change(nsIRDFResource* aSource,
  547. nsIRDFResource* aProperty,
  548. nsIRDFNode* aOldTarget,
  549. nsIRDFNode* aNewTarget)
  550. {
  551. nsresult rv;
  552. if (IsLoading() || mIsWritable) {
  553. rv = mInner->Change(aSource, aProperty, aOldTarget, aNewTarget);
  554. if (!IsLoading() && rv == NS_RDF_ASSERTION_ACCEPTED)
  555. mIsDirty = true;
  556. }
  557. else {
  558. rv = NS_RDF_ASSERTION_REJECTED;
  559. }
  560. return rv;
  561. }
  562. NS_IMETHODIMP
  563. RDFXMLDataSourceImpl::Move(nsIRDFResource* aOldSource,
  564. nsIRDFResource* aNewSource,
  565. nsIRDFResource* aProperty,
  566. nsIRDFNode* aTarget)
  567. {
  568. nsresult rv;
  569. if (IsLoading() || mIsWritable) {
  570. rv = mInner->Move(aOldSource, aNewSource, aProperty, aTarget);
  571. if (!IsLoading() && rv == NS_RDF_ASSERTION_ACCEPTED)
  572. mIsDirty = true;
  573. }
  574. else {
  575. rv = NS_RDF_ASSERTION_REJECTED;
  576. }
  577. return rv;
  578. }
  579. nsresult
  580. RDFXMLDataSourceImpl::rdfXMLFlush(nsIURI *aURI)
  581. {
  582. nsresult rv;
  583. {
  584. // Quick and dirty check to see if we're in XPCOM shutdown. If
  585. // we are, we're screwed: it's too late to serialize because
  586. // many of the services that we'll need to acquire to properly
  587. // write the file will be unaquirable.
  588. NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
  589. nsCOMPtr<nsIRDFService> dummy = do_GetService(kRDFServiceCID, &rv);
  590. if (NS_FAILED(rv)) {
  591. NS_WARNING("unable to Flush() dirty datasource during XPCOM shutdown");
  592. return rv;
  593. }
  594. }
  595. // Is it a file? If so, we can write to it. Some day, it'd be nice
  596. // if we didn't care what kind of stream this was...
  597. nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aURI);
  598. if (fileURL) {
  599. nsCOMPtr<nsIFile> file;
  600. fileURL->GetFile(getter_AddRefs(file));
  601. if (file) {
  602. // get a safe output stream, so we don't clobber the datasource file unless
  603. // all the writes succeeded.
  604. nsCOMPtr<nsIOutputStream> out;
  605. rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(out),
  606. file,
  607. PR_WRONLY | PR_CREATE_FILE,
  608. /*octal*/ 0666,
  609. 0);
  610. if (NS_FAILED(rv)) return rv;
  611. nsCOMPtr<nsIOutputStream> bufferedOut;
  612. rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOut), out, 4096);
  613. if (NS_FAILED(rv)) return rv;
  614. rv = Serialize(bufferedOut);
  615. if (NS_FAILED(rv)) return rv;
  616. // All went ok. Maybe except for problems in Write(), but the stream detects
  617. // that for us
  618. nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(bufferedOut, &rv);
  619. if (NS_FAILED(rv)) return rv;
  620. rv = safeStream->Finish();
  621. if (NS_FAILED(rv)) {
  622. NS_WARNING("failed to save datasource file! possible dataloss");
  623. return rv;
  624. }
  625. }
  626. }
  627. return NS_OK;
  628. }
  629. NS_IMETHODIMP
  630. RDFXMLDataSourceImpl::FlushTo(const char *aURI)
  631. {
  632. NS_PRECONDITION(aURI != nullptr, "not initialized");
  633. if (!aURI)
  634. return NS_ERROR_NULL_POINTER;
  635. // XXX this is a hack: any "file:" URI is considered writable. All
  636. // others are considered read-only.
  637. if ((PL_strncmp(aURI, kFileURIPrefix, sizeof(kFileURIPrefix) - 1) != 0) &&
  638. (PL_strncmp(aURI, kResourceURIPrefix, sizeof(kResourceURIPrefix) - 1) != 0))
  639. {
  640. return NS_ERROR_ILLEGAL_VALUE;
  641. }
  642. nsCOMPtr<nsIURI> url;
  643. nsresult rv = NS_NewURI(getter_AddRefs(url), aURI);
  644. if (NS_FAILED(rv))
  645. return rv;
  646. rv = rdfXMLFlush(url);
  647. return rv;
  648. }
  649. NS_IMETHODIMP
  650. RDFXMLDataSourceImpl::Flush(void)
  651. {
  652. if (!mIsWritable || !mIsDirty)
  653. return NS_OK;
  654. // while it is not fatal if mURL is not set,
  655. // indicate failure since we can't flush back to an unknown origin
  656. if (! mURL)
  657. return NS_ERROR_NOT_INITIALIZED;
  658. if (MOZ_LOG_TEST(gLog, LogLevel::Debug)) {
  659. MOZ_LOG(gLog, LogLevel::Debug,
  660. ("rdfxml[%p] flush(%s)", this, mURL->GetSpecOrDefault().get()));
  661. }
  662. nsresult rv;
  663. if (NS_SUCCEEDED(rv = rdfXMLFlush(mURL)))
  664. {
  665. mIsDirty = false;
  666. }
  667. return rv;
  668. }
  669. //----------------------------------------------------------------------
  670. //
  671. // nsIRDFXMLDataSource methods
  672. //
  673. NS_IMETHODIMP
  674. RDFXMLDataSourceImpl::GetReadOnly(bool* aIsReadOnly)
  675. {
  676. *aIsReadOnly = !mIsWritable;
  677. return NS_OK;
  678. }
  679. NS_IMETHODIMP
  680. RDFXMLDataSourceImpl::SetReadOnly(bool aIsReadOnly)
  681. {
  682. if (mIsWritable && aIsReadOnly)
  683. mIsWritable = false;
  684. return NS_OK;
  685. }
  686. // nsIChannelEventSink
  687. // This code is copied from nsSameOriginChecker::OnChannelRedirect. See
  688. // bug 475940 on providing this code in a shared location.
  689. NS_IMETHODIMP
  690. RDFXMLDataSourceImpl::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
  691. nsIChannel *aNewChannel,
  692. uint32_t aFlags,
  693. nsIAsyncVerifyRedirectCallback *cb)
  694. {
  695. NS_PRECONDITION(aNewChannel, "Redirecting to null channel?");
  696. nsresult rv;
  697. nsCOMPtr<nsIScriptSecurityManager> secMan =
  698. do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
  699. NS_ENSURE_SUCCESS(rv, rv);
  700. nsCOMPtr<nsIPrincipal> oldPrincipal;
  701. secMan->GetChannelResultPrincipal(aOldChannel, getter_AddRefs(oldPrincipal));
  702. nsCOMPtr<nsIURI> newURI;
  703. aNewChannel->GetURI(getter_AddRefs(newURI));
  704. nsCOMPtr<nsIURI> newOriginalURI;
  705. aNewChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
  706. NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI);
  707. rv = oldPrincipal->CheckMayLoad(newURI, false, false);
  708. if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
  709. rv = oldPrincipal->CheckMayLoad(newOriginalURI, false, false);
  710. }
  711. if (NS_FAILED(rv))
  712. return rv;
  713. cb->OnRedirectVerifyCallback(NS_OK);
  714. return NS_OK;
  715. }
  716. NS_IMETHODIMP
  717. RDFXMLDataSourceImpl::Refresh(bool aBlocking)
  718. {
  719. nsAutoCString spec;
  720. if (mURL) {
  721. spec = mURL->GetSpecOrDefault();
  722. }
  723. MOZ_LOG(gLog, LogLevel::Debug,
  724. ("rdfxml[%p] refresh(%s) %sblocking", this, spec.get(), (aBlocking ? "" : "non")));
  725. // If an asynchronous load is already pending, then just let it do
  726. // the honors.
  727. if (IsLoading()) {
  728. MOZ_LOG(gLog, LogLevel::Debug,
  729. ("rdfxml[%p] refresh(%s) a load was pending", this, spec.get()));
  730. if (aBlocking) {
  731. NS_WARNING("blocking load requested when async load pending");
  732. return NS_ERROR_FAILURE;
  733. }
  734. else {
  735. return NS_OK;
  736. }
  737. }
  738. if (! mURL)
  739. return NS_ERROR_FAILURE;
  740. nsCOMPtr<nsIRDFXMLParser> parser = do_CreateInstance("@mozilla.org/rdf/xml-parser;1");
  741. if (! parser)
  742. return NS_ERROR_FAILURE;
  743. nsresult rv = parser->ParseAsync(this, mURL, getter_AddRefs(mListener));
  744. if (NS_FAILED(rv)) return rv;
  745. if (aBlocking) {
  746. rv = BlockingParse(mURL, this);
  747. mListener = nullptr; // release the parser
  748. if (NS_FAILED(rv)) return rv;
  749. }
  750. else {
  751. // Null LoadGroup ?
  752. nsCOMPtr<nsIChannel> channel;
  753. rv = NS_NewChannel(getter_AddRefs(channel),
  754. mURL,
  755. nsContentUtils::GetSystemPrincipal(),
  756. nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
  757. nsIContentPolicy::TYPE_OTHER,
  758. nullptr, // aLoadGroup
  759. this); // aCallbacks
  760. NS_ENSURE_SUCCESS(rv, rv);
  761. rv = channel->AsyncOpen2(this);
  762. NS_ENSURE_SUCCESS(rv, rv);
  763. // So we don't try to issue two asynchronous loads at once.
  764. mLoadState = eLoadState_Pending;
  765. }
  766. return NS_OK;
  767. }
  768. NS_IMETHODIMP
  769. RDFXMLDataSourceImpl::BeginLoad(void)
  770. {
  771. if (MOZ_LOG_TEST(gLog, LogLevel::Debug)) {
  772. MOZ_LOG(gLog, LogLevel::Debug,
  773. ("rdfxml[%p] begin-load(%s)", this,
  774. mURL ? mURL->GetSpecOrDefault().get() : ""));
  775. }
  776. mLoadState = eLoadState_Loading;
  777. for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
  778. // Make sure to hold a strong reference to the observer so
  779. // that it doesn't go away in this call if it removes itself
  780. // as an observer
  781. nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
  782. if (obs) {
  783. obs->OnBeginLoad(this);
  784. }
  785. }
  786. return NS_OK;
  787. }
  788. NS_IMETHODIMP
  789. RDFXMLDataSourceImpl::Interrupt(void)
  790. {
  791. if (MOZ_LOG_TEST(gLog, LogLevel::Debug)) {
  792. MOZ_LOG(gLog, LogLevel::Debug,
  793. ("rdfxml[%p] interrupt(%s)", this,
  794. mURL ? mURL->GetSpecOrDefault().get() : ""));
  795. }
  796. for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
  797. // Make sure to hold a strong reference to the observer so
  798. // that it doesn't go away in this call if it removes itself
  799. // as an observer
  800. nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
  801. if (obs) {
  802. obs->OnInterrupt(this);
  803. }
  804. }
  805. return NS_OK;
  806. }
  807. NS_IMETHODIMP
  808. RDFXMLDataSourceImpl::Resume(void)
  809. {
  810. if (MOZ_LOG_TEST(gLog, LogLevel::Debug)) {
  811. MOZ_LOG(gLog, LogLevel::Debug,
  812. ("rdfxml[%p] resume(%s)", this,
  813. mURL ? mURL->GetSpecOrDefault().get() : ""));
  814. }
  815. for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
  816. // Make sure to hold a strong reference to the observer so
  817. // that it doesn't go away in this call if it removes itself
  818. // as an observer
  819. nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
  820. if (obs) {
  821. obs->OnResume(this);
  822. }
  823. }
  824. return NS_OK;
  825. }
  826. NS_IMETHODIMP
  827. RDFXMLDataSourceImpl::EndLoad(void)
  828. {
  829. if (MOZ_LOG_TEST(gLog, LogLevel::Debug)) {
  830. MOZ_LOG(gLog, LogLevel::Debug,
  831. ("rdfxml[%p] end-load(%s)", this,
  832. mURL ? mURL->GetSpecOrDefault().get() : ""));
  833. }
  834. mLoadState = eLoadState_Loaded;
  835. // Clear out any unmarked assertions from the datasource.
  836. nsCOMPtr<nsIRDFPurgeableDataSource> gcable = do_QueryInterface(mInner);
  837. if (gcable) {
  838. gcable->Sweep();
  839. }
  840. // Notify load observers
  841. for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
  842. // Make sure to hold a strong reference to the observer so
  843. // that it doesn't go away in this call if it removes itself
  844. // as an observer
  845. nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
  846. if (obs) {
  847. obs->OnEndLoad(this);
  848. }
  849. }
  850. return NS_OK;
  851. }
  852. NS_IMETHODIMP
  853. RDFXMLDataSourceImpl::AddNameSpace(nsIAtom* aPrefix, const nsString& aURI)
  854. {
  855. mNameSpaces.Put(aURI, aPrefix);
  856. return NS_OK;
  857. }
  858. NS_IMETHODIMP
  859. RDFXMLDataSourceImpl::AddXMLSinkObserver(nsIRDFXMLSinkObserver* aObserver)
  860. {
  861. if (! aObserver)
  862. return NS_ERROR_NULL_POINTER;
  863. mObservers.AppendObject(aObserver);
  864. return NS_OK;
  865. }
  866. NS_IMETHODIMP
  867. RDFXMLDataSourceImpl::RemoveXMLSinkObserver(nsIRDFXMLSinkObserver* aObserver)
  868. {
  869. if (! aObserver)
  870. return NS_ERROR_NULL_POINTER;
  871. mObservers.RemoveObject(aObserver);
  872. return NS_OK;
  873. }
  874. //----------------------------------------------------------------------
  875. //
  876. // nsIRequestObserver
  877. //
  878. NS_IMETHODIMP
  879. RDFXMLDataSourceImpl::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
  880. {
  881. return mListener->OnStartRequest(request, ctxt);
  882. }
  883. NS_IMETHODIMP
  884. RDFXMLDataSourceImpl::OnStopRequest(nsIRequest *request,
  885. nsISupports *ctxt,
  886. nsresult status)
  887. {
  888. if (NS_FAILED(status)) {
  889. for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
  890. // Make sure to hold a strong reference to the observer so
  891. // that it doesn't go away in this call if it removes
  892. // itself as an observer
  893. nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
  894. if (obs) {
  895. obs->OnError(this, status, nullptr);
  896. }
  897. }
  898. }
  899. nsresult rv;
  900. rv = mListener->OnStopRequest(request, ctxt, status);
  901. mListener = nullptr; // release the parser
  902. return rv;
  903. }
  904. //----------------------------------------------------------------------
  905. //
  906. // nsIStreamListener
  907. //
  908. NS_IMETHODIMP
  909. RDFXMLDataSourceImpl::OnDataAvailable(nsIRequest *request,
  910. nsISupports *ctxt,
  911. nsIInputStream *inStr,
  912. uint64_t sourceOffset,
  913. uint32_t count)
  914. {
  915. return mListener->OnDataAvailable(request, ctxt, inStr, sourceOffset, count);
  916. }
  917. //----------------------------------------------------------------------
  918. //
  919. // nsIRDFXMLSource
  920. //
  921. NS_IMETHODIMP
  922. RDFXMLDataSourceImpl::Serialize(nsIOutputStream* aStream)
  923. {
  924. nsresult rv;
  925. nsCOMPtr<nsIRDFXMLSerializer> serializer
  926. = do_CreateInstance("@mozilla.org/rdf/xml-serializer;1", &rv);
  927. if (! serializer)
  928. return rv;
  929. rv = serializer->Init(this);
  930. if (NS_FAILED(rv)) return rv;
  931. // Add any namespace information that we picked up when reading
  932. // the RDF/XML
  933. nsNameSpaceMap::const_iterator last = mNameSpaces.last();
  934. for (nsNameSpaceMap::const_iterator iter = mNameSpaces.first();
  935. iter != last; ++iter) {
  936. // We might wanna change nsIRDFXMLSerializer to nsACString and
  937. // use a heap allocated buffer here in the future.
  938. NS_ConvertUTF8toUTF16 uri(iter->mURI);
  939. serializer->AddNameSpace(iter->mPrefix, uri);
  940. }
  941. // Serialize!
  942. nsCOMPtr<nsIRDFXMLSource> source = do_QueryInterface(serializer);
  943. if (! source)
  944. return NS_ERROR_FAILURE;
  945. return source->Serialize(aStream);
  946. }