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