rdf/base/src/nsRDFXMLDataSource.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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/. */
     6 /*
     8   A data source that can read itself from and write itself to an
     9   RDF/XML stream.
    11   For more information on the RDF/XML syntax,
    12   see http://www.w3.org/TR/REC-rdf-syntax/.
    14   This code is based on the final W3C Recommendation,
    15   http://www.w3.org/TR/1999/REC-rdf-syntax-19990222.
    18   TO DO
    19   -----
    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.
    28   2) Implement a more terse output for "typed" nodes; that is, instead
    29      of "RDF:Description type='ns:foo'", just output "ns:foo".
    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"'.
    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?
    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.
    49   Logging
    50   -------
    52   To turn on logging for this module, set
    54     NSPR_LOG_MODULES=nsRDFXMLDataSource:5
    56  */
    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 "nsIServiceManager.h"
    75 #include "nsIStreamListener.h"
    76 #include "nsIURL.h"
    77 #include "nsIFileURL.h"
    78 #include "nsNetUtil.h"
    79 #include "nsIChannel.h"
    80 #include "nsRDFCID.h"
    81 #include "nsRDFBaseDataSources.h"
    82 #include "nsCOMArray.h"
    83 #include "nsXPIDLString.h"
    84 #include "plstr.h"
    85 #include "prio.h"
    86 #include "prthread.h"
    87 #include "rdf.h"
    88 #include "rdfutil.h"
    89 #include "prlog.h"
    90 #include "nsNameSpaceMap.h"
    91 #include "nsCRT.h"
    92 #include "nsCycleCollectionParticipant.h"
    93 #include "nsIScriptSecurityManager.h"
    94 #include "nsIChannelEventSink.h"
    95 #include "nsIAsyncVerifyRedirectCallback.h"
    96 #include "nsNetUtil.h"
    98 #include "rdfIDataSource.h"
   100 //----------------------------------------------------------------------
   101 //
   102 // RDFXMLDataSourceImpl
   103 //
   105 class RDFXMLDataSourceImpl : public nsIRDFDataSource,
   106                              public nsIRDFRemoteDataSource,
   107                              public nsIRDFXMLSink,
   108                              public nsIRDFXMLSource,
   109                              public nsIStreamListener,
   110                              public rdfIDataSource,
   111                              public nsIInterfaceRequestor,
   112                              public nsIChannelEventSink
   113 {
   114 protected:
   115     enum LoadState {
   116         eLoadState_Unloaded,
   117         eLoadState_Pending,
   118         eLoadState_Loading,
   119         eLoadState_Loaded
   120     };
   122     nsCOMPtr<nsIRDFDataSource> mInner;
   123     bool                mIsWritable;    // true if the document can be written back
   124     bool                mIsDirty;       // true if the document should be written back
   125     LoadState           mLoadState;     // what we're doing now
   126     nsCOMArray<nsIRDFXMLSinkObserver> mObservers;
   127     nsCOMPtr<nsIURI>    mURL;
   128     nsCOMPtr<nsIStreamListener> mListener;
   129     nsNameSpaceMap      mNameSpaces;
   131     // pseudo-constants
   132     static int32_t gRefCnt;
   133     static nsIRDFService* gRDFService;
   135 #ifdef PR_LOGGING
   136     static PRLogModuleInfo* gLog;
   137 #endif
   139     nsresult Init();
   140     RDFXMLDataSourceImpl(void);
   141     virtual ~RDFXMLDataSourceImpl(void);
   142     nsresult rdfXMLFlush(nsIURI *aURI);
   144     friend nsresult
   145     NS_NewRDFXMLDataSource(nsIRDFDataSource** aResult);
   147     inline bool IsLoading() {
   148         return (mLoadState == eLoadState_Pending) || 
   149                (mLoadState == eLoadState_Loading);
   150     }
   152 public:
   153     // nsISupports
   154     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   155     NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(RDFXMLDataSourceImpl,
   156                                              nsIRDFDataSource)
   158     // nsIRDFDataSource
   159     NS_IMETHOD GetURI(char* *uri);
   161     NS_IMETHOD GetSource(nsIRDFResource* property,
   162                          nsIRDFNode* target,
   163                          bool tv,
   164                          nsIRDFResource** source) {
   165         return mInner->GetSource(property, target, tv, source);
   166     }
   168     NS_IMETHOD GetSources(nsIRDFResource* property,
   169                           nsIRDFNode* target,
   170                           bool tv,
   171                           nsISimpleEnumerator** sources) {
   172         return mInner->GetSources(property, target, tv, sources);
   173     }
   175     NS_IMETHOD GetTarget(nsIRDFResource* source,
   176                          nsIRDFResource* property,
   177                          bool tv,
   178                          nsIRDFNode** target) {
   179         return mInner->GetTarget(source, property, tv, target);
   180     }
   182     NS_IMETHOD GetTargets(nsIRDFResource* source,
   183                           nsIRDFResource* property,
   184                           bool tv,
   185                           nsISimpleEnumerator** targets) {
   186         return mInner->GetTargets(source, property, tv, targets);
   187     }
   189     NS_IMETHOD Assert(nsIRDFResource* aSource,
   190                       nsIRDFResource* aProperty,
   191                       nsIRDFNode* aTarget,
   192                       bool tv);
   194     NS_IMETHOD Unassert(nsIRDFResource* source,
   195                         nsIRDFResource* property,
   196                         nsIRDFNode* target);
   198     NS_IMETHOD Change(nsIRDFResource* aSource,
   199                       nsIRDFResource* aProperty,
   200                       nsIRDFNode* aOldTarget,
   201                       nsIRDFNode* aNewTarget);
   203     NS_IMETHOD Move(nsIRDFResource* aOldSource,
   204                     nsIRDFResource* aNewSource,
   205                     nsIRDFResource* aProperty,
   206                     nsIRDFNode* aTarget);
   208     NS_IMETHOD HasAssertion(nsIRDFResource* source,
   209                             nsIRDFResource* property,
   210                             nsIRDFNode* target,
   211                             bool tv,
   212                             bool* hasAssertion) {
   213         return mInner->HasAssertion(source, property, target, tv, hasAssertion);
   214     }
   216     NS_IMETHOD AddObserver(nsIRDFObserver* aObserver) {
   217         return mInner->AddObserver(aObserver);
   218     }
   220     NS_IMETHOD RemoveObserver(nsIRDFObserver* aObserver) {
   221         return mInner->RemoveObserver(aObserver);
   222     }
   224     NS_IMETHOD HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *_retval) {
   225         return mInner->HasArcIn(aNode, aArc, _retval);
   226     }
   228     NS_IMETHOD HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *_retval) {
   229         return mInner->HasArcOut(aSource, aArc, _retval);
   230     }
   232     NS_IMETHOD ArcLabelsIn(nsIRDFNode* node,
   233                            nsISimpleEnumerator** labels) {
   234         return mInner->ArcLabelsIn(node, labels);
   235     }
   237     NS_IMETHOD ArcLabelsOut(nsIRDFResource* source,
   238                             nsISimpleEnumerator** labels) {
   239         return mInner->ArcLabelsOut(source, labels);
   240     }
   242     NS_IMETHOD GetAllResources(nsISimpleEnumerator** aResult) {
   243         return mInner->GetAllResources(aResult);
   244     }
   246     NS_IMETHOD GetAllCmds(nsIRDFResource* source,
   247                               nsISimpleEnumerator/*<nsIRDFResource>*/** commands) {
   248         return mInner->GetAllCmds(source, commands);
   249     }
   251     NS_IMETHOD IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
   252                                 nsIRDFResource*   aCommand,
   253                                 nsISupportsArray/*<nsIRDFResource>*/* aArguments,
   254                                 bool* aResult) {
   255         return mInner->IsCommandEnabled(aSources, aCommand, aArguments, aResult);
   256     }
   258     NS_IMETHOD DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
   259                          nsIRDFResource*   aCommand,
   260                          nsISupportsArray/*<nsIRDFResource>*/* aArguments) {
   261         // XXX Uh oh, this could cause problems wrt. the "dirty" flag
   262         // if it changes the in-memory store's internal state.
   263         return mInner->DoCommand(aSources, aCommand, aArguments);
   264     }
   266     NS_IMETHOD BeginUpdateBatch() {
   267         return mInner->BeginUpdateBatch();
   268     }
   270     NS_IMETHOD EndUpdateBatch() {
   271         return mInner->EndUpdateBatch();
   272     }
   274     // nsIRDFRemoteDataSource interface
   275     NS_DECL_NSIRDFREMOTEDATASOURCE
   277     // nsIRDFXMLSink interface
   278     NS_DECL_NSIRDFXMLSINK
   280     // nsIRDFXMLSource interface
   281     NS_DECL_NSIRDFXMLSOURCE
   283     // nsIRequestObserver
   284     NS_DECL_NSIREQUESTOBSERVER
   286     // nsIStreamListener
   287     NS_DECL_NSISTREAMLISTENER
   289     // nsIInterfaceRequestor
   290     NS_DECL_NSIINTERFACEREQUESTOR
   292     // nsIChannelEventSink
   293     NS_DECL_NSICHANNELEVENTSINK
   295     // rdfIDataSource
   296     NS_IMETHOD VisitAllSubjects(rdfITripleVisitor *aVisitor) {
   297         nsresult rv;
   298         nsCOMPtr<rdfIDataSource> rdfds = do_QueryInterface(mInner, &rv);
   299         if (NS_FAILED(rv)) return rv;
   300         return rdfds->VisitAllSubjects(aVisitor);
   301     } 
   303     NS_IMETHOD VisitAllTriples(rdfITripleVisitor *aVisitor) {
   304         nsresult rv;
   305         nsCOMPtr<rdfIDataSource> rdfds = do_QueryInterface(mInner, &rv);
   306         if (NS_FAILED(rv)) return rv;
   307         return rdfds->VisitAllTriples(aVisitor);
   308     } 
   310     // Implementation methods
   311     bool
   312     MakeQName(nsIRDFResource* aResource,
   313               nsString& property,
   314               nsString& nameSpacePrefix,
   315               nsString& nameSpaceURI);
   317     nsresult
   318     SerializeAssertion(nsIOutputStream* aStream,
   319                        nsIRDFResource* aResource,
   320                        nsIRDFResource* aProperty,
   321                        nsIRDFNode* aValue);
   323     nsresult
   324     SerializeProperty(nsIOutputStream* aStream,
   325                       nsIRDFResource* aResource,
   326                       nsIRDFResource* aProperty);
   328     bool
   329     IsContainerProperty(nsIRDFResource* aProperty);
   331     nsresult
   332     SerializeDescription(nsIOutputStream* aStream,
   333                          nsIRDFResource* aResource);
   335     nsresult
   336     SerializeMember(nsIOutputStream* aStream,
   337                     nsIRDFResource* aContainer,
   338                     nsIRDFNode* aMember);
   340     nsresult
   341     SerializeContainer(nsIOutputStream* aStream,
   342                        nsIRDFResource* aContainer);
   344     nsresult
   345     SerializePrologue(nsIOutputStream* aStream);
   347     nsresult
   348     SerializeEpilogue(nsIOutputStream* aStream);
   350     bool
   351     IsA(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType);
   353 protected:
   354     nsresult
   355     BlockingParse(nsIURI* aURL, nsIStreamListener* aConsumer);
   356 };
   358 int32_t         RDFXMLDataSourceImpl::gRefCnt = 0;
   359 nsIRDFService*  RDFXMLDataSourceImpl::gRDFService;
   361 #ifdef PR_LOGGING
   362 PRLogModuleInfo* RDFXMLDataSourceImpl::gLog;
   363 #endif
   365 static const char kFileURIPrefix[] = "file:";
   366 static const char kResourceURIPrefix[] = "resource:";
   369 //----------------------------------------------------------------------
   371 nsresult
   372 NS_NewRDFXMLDataSource(nsIRDFDataSource** aResult)
   373 {
   374     NS_PRECONDITION(aResult != nullptr, "null ptr");
   375     if (! aResult)
   376         return NS_ERROR_NULL_POINTER;
   378     RDFXMLDataSourceImpl* datasource = new RDFXMLDataSourceImpl();
   379     if (! datasource)
   380         return NS_ERROR_OUT_OF_MEMORY;
   382     nsresult rv;
   383     rv = datasource->Init();
   385     if (NS_FAILED(rv)) {
   386         delete datasource;
   387         return rv;
   388     }
   390     NS_ADDREF(datasource);
   391     *aResult = datasource;
   392     return NS_OK;
   393 }
   396 RDFXMLDataSourceImpl::RDFXMLDataSourceImpl(void)
   397     : mIsWritable(true),
   398       mIsDirty(false),
   399       mLoadState(eLoadState_Unloaded)
   400 {
   401 #ifdef PR_LOGGING
   402     if (! gLog)
   403         gLog = PR_NewLogModule("nsRDFXMLDataSource");
   404 #endif
   405 }
   408 nsresult
   409 RDFXMLDataSourceImpl::Init()
   410 {
   411     nsresult rv;
   412     NS_DEFINE_CID(kRDFInMemoryDataSourceCID, NS_RDFINMEMORYDATASOURCE_CID);
   413     mInner = do_CreateInstance(kRDFInMemoryDataSourceCID, &rv);
   414     if (NS_FAILED(rv)) return rv;
   416     if (gRefCnt++ == 0) {
   417         NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
   418         rv = CallGetService(kRDFServiceCID, &gRDFService);
   420         NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF service");
   421         if (NS_FAILED(rv)) return rv;
   422     }
   424     return NS_OK;
   425 }
   428 RDFXMLDataSourceImpl::~RDFXMLDataSourceImpl(void)
   429 {
   430     // Unregister first so that nobody else tries to get us.
   431     (void) gRDFService->UnregisterDataSource(this);
   433     // Now flush contents
   434     (void) Flush();
   436     // Release RDF/XML sink observers
   437     mObservers.Clear();
   439     if (--gRefCnt == 0)
   440         NS_IF_RELEASE(gRDFService);
   441 }
   443 NS_IMPL_CYCLE_COLLECTION_CLASS(RDFXMLDataSourceImpl)
   445 NS_IMPL_CYCLE_COLLECTION_UNLINK_0(RDFXMLDataSourceImpl)
   446 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(RDFXMLDataSourceImpl)
   447     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInner)
   448 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   450 NS_IMPL_CYCLE_COLLECTING_ADDREF(RDFXMLDataSourceImpl)
   451 NS_IMPL_CYCLE_COLLECTING_RELEASE(RDFXMLDataSourceImpl)
   453 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RDFXMLDataSourceImpl)
   454     NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource)
   455     NS_INTERFACE_MAP_ENTRY(nsIRDFRemoteDataSource)
   456     NS_INTERFACE_MAP_ENTRY(nsIRDFXMLSink)
   457     NS_INTERFACE_MAP_ENTRY(nsIRDFXMLSource)
   458     NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
   459     NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
   460     NS_INTERFACE_MAP_ENTRY(rdfIDataSource)
   461     NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
   462     NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
   463     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRDFDataSource)
   464 NS_INTERFACE_MAP_END
   466 // nsIInterfaceRequestor
   467 NS_IMETHODIMP
   468 RDFXMLDataSourceImpl::GetInterface(const nsIID& aIID, void** aSink)
   469 {
   470   return QueryInterface(aIID, aSink);
   471 }
   473 nsresult
   474 RDFXMLDataSourceImpl::BlockingParse(nsIURI* aURL, nsIStreamListener* aConsumer)
   475 {
   476     nsresult rv;
   478     // XXX I really hate the way that we're spoon-feeding this stuff
   479     // to the parser: it seems like this is something that netlib
   480     // should be able to do by itself.
   482     nsCOMPtr<nsIChannel> channel;
   483     nsCOMPtr<nsIRequest> request;
   485     // Null LoadGroup ?
   486     rv = NS_NewChannel(getter_AddRefs(channel), aURL, nullptr);
   487     if (NS_FAILED(rv)) return rv;
   488     nsCOMPtr<nsIInputStream> in;
   489     rv = channel->Open(getter_AddRefs(in));
   491     // Report success if the file doesn't exist, but propagate other errors.
   492     if (rv == NS_ERROR_FILE_NOT_FOUND) return NS_OK;
   493     if (NS_FAILED(rv)) return rv;
   495     if (! in) {
   496         NS_ERROR("no input stream");
   497         return NS_ERROR_FAILURE;
   498     }
   500     // Wrap the channel's input stream in a buffered stream to ensure that
   501     // ReadSegments is implemented (which OnDataAvailable expects).
   502     nsCOMPtr<nsIInputStream> bufStream;
   503     rv = NS_NewBufferedInputStream(getter_AddRefs(bufStream), in,
   504                                    4096 /* buffer size */);
   505     if (NS_FAILED(rv)) return rv;
   507     // Notify load observers
   508     int32_t i;
   509     for (i = mObservers.Count() - 1; i >= 0; --i) {
   510         // Make sure to hold a strong reference to the observer so
   511         // that it doesn't go away in this call if it removes itself
   512         // as an observer
   513         nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
   515         if (obs) {
   516             obs->OnBeginLoad(this);
   517         }
   518     }
   520     rv = aConsumer->OnStartRequest(channel, nullptr);
   522     uint64_t offset = 0;
   523     while (NS_SUCCEEDED(rv)) {
   524         // Skip ODA if the channel is canceled
   525         channel->GetStatus(&rv);
   526         if (NS_FAILED(rv))
   527             break;
   529         uint64_t avail;
   530         if (NS_FAILED(rv = bufStream->Available(&avail)))
   531             break; // error
   533         if (avail == 0)
   534             break; // eof
   536         if (avail > UINT32_MAX)
   537             avail = UINT32_MAX;
   539         rv = aConsumer->OnDataAvailable(channel, nullptr, bufStream, offset, (uint32_t)avail);
   540         if (NS_SUCCEEDED(rv))
   541             offset += avail;
   542     }
   544     if (NS_FAILED(rv))
   545         channel->Cancel(rv);
   547     channel->GetStatus(&rv);
   548     aConsumer->OnStopRequest(channel, nullptr, rv);
   550     // Notify load observers
   551     for (i = mObservers.Count() - 1; i >= 0; --i) {
   552         // Make sure to hold a strong reference to the observer so
   553         // that it doesn't go away in this call if it removes itself
   554         // as an observer
   555         nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
   557         if (obs) {
   558             if (NS_FAILED(rv))
   559                 obs->OnError(this, rv, nullptr);
   561             obs->OnEndLoad(this);
   562         }
   563     }
   565     return rv;
   566 }
   568 NS_IMETHODIMP
   569 RDFXMLDataSourceImpl::GetLoaded(bool* _result)
   570 {
   571     *_result = (mLoadState == eLoadState_Loaded);
   572     return NS_OK;
   573 }
   575 NS_IMETHODIMP
   576 RDFXMLDataSourceImpl::Init(const char* uri)
   577 {
   578     NS_PRECONDITION(mInner != nullptr, "not initialized");
   579     if (! mInner)
   580         return NS_ERROR_OUT_OF_MEMORY;
   582     nsresult rv;
   584     rv = NS_NewURI(getter_AddRefs(mURL), nsDependentCString(uri));
   585     if (NS_FAILED(rv)) return rv;
   587     // XXX this is a hack: any "file:" URI is considered writable. All
   588     // others are considered read-only.
   589     if ((PL_strncmp(uri, kFileURIPrefix, sizeof(kFileURIPrefix) - 1) != 0) &&
   590         (PL_strncmp(uri, kResourceURIPrefix, sizeof(kResourceURIPrefix) - 1) != 0)) {
   591         mIsWritable = false;
   592     }
   594     rv = gRDFService->RegisterDataSource(this, false);
   595     if (NS_FAILED(rv)) return rv;
   597     return NS_OK;
   598 }
   601 NS_IMETHODIMP
   602 RDFXMLDataSourceImpl::GetURI(char* *aURI)
   603 {
   604     *aURI = nullptr;
   605     if (!mURL) {
   606         return NS_OK;
   607     }
   609     nsAutoCString spec;
   610     mURL->GetSpec(spec);
   611     *aURI = ToNewCString(spec);
   612     if (!*aURI) {
   613         return NS_ERROR_OUT_OF_MEMORY;
   614     }
   616     return NS_OK;
   617 }
   619 NS_IMETHODIMP
   620 RDFXMLDataSourceImpl::Assert(nsIRDFResource* aSource,
   621                              nsIRDFResource* aProperty,
   622                              nsIRDFNode* aTarget,
   623                              bool aTruthValue)
   624 {
   625     // We don't accept assertions unless we're writable (except in the
   626     // case that we're actually _reading_ the datasource in).
   627     nsresult rv;
   629     if (IsLoading()) {
   630         bool hasAssertion = false;
   632         nsCOMPtr<nsIRDFPurgeableDataSource> gcable = do_QueryInterface(mInner);
   633         if (gcable) {
   634             rv = gcable->Mark(aSource, aProperty, aTarget, aTruthValue, &hasAssertion);
   635             if (NS_FAILED(rv)) return rv;
   636         }
   638         rv = NS_RDF_ASSERTION_ACCEPTED;
   640         if (! hasAssertion) {
   641             rv = mInner->Assert(aSource, aProperty, aTarget, aTruthValue);
   643             if (NS_SUCCEEDED(rv) && gcable) {
   644                 // Now mark the new assertion, so it doesn't get
   645                 // removed when we sweep. Ignore rv, because we want
   646                 // to return what mInner->Assert() gave us.
   647                 bool didMark;
   648                 (void) gcable->Mark(aSource, aProperty, aTarget, aTruthValue, &didMark);
   649             }
   651             if (NS_FAILED(rv)) return rv;
   652         }
   654         return rv;
   655     }
   656     else if (mIsWritable) {
   657         rv = mInner->Assert(aSource, aProperty, aTarget, aTruthValue);
   659         if (rv == NS_RDF_ASSERTION_ACCEPTED)
   660             mIsDirty = true;
   662         return rv;
   663     }
   664     else {
   665         return NS_RDF_ASSERTION_REJECTED;
   666     }
   667 }
   670 NS_IMETHODIMP
   671 RDFXMLDataSourceImpl::Unassert(nsIRDFResource* source,
   672                                nsIRDFResource* property,
   673                                nsIRDFNode* target)
   674 {
   675     // We don't accept assertions unless we're writable (except in the
   676     // case that we're actually _reading_ the datasource in).
   677     nsresult rv;
   679     if (IsLoading() || mIsWritable) {
   680         rv = mInner->Unassert(source, property, target);
   681         if (!IsLoading() && rv == NS_RDF_ASSERTION_ACCEPTED)
   682             mIsDirty = true;
   683     }
   684     else {
   685         rv = NS_RDF_ASSERTION_REJECTED;
   686     }
   688     return rv;
   689 }
   691 NS_IMETHODIMP
   692 RDFXMLDataSourceImpl::Change(nsIRDFResource* aSource,
   693                              nsIRDFResource* aProperty,
   694                              nsIRDFNode* aOldTarget,
   695                              nsIRDFNode* aNewTarget)
   696 {
   697     nsresult rv;
   699     if (IsLoading() || mIsWritable) {
   700         rv = mInner->Change(aSource, aProperty, aOldTarget, aNewTarget);
   702         if (!IsLoading() && rv == NS_RDF_ASSERTION_ACCEPTED)
   703             mIsDirty = true;
   704     }
   705     else {
   706         rv = NS_RDF_ASSERTION_REJECTED;
   707     }
   709     return rv;
   710 }
   712 NS_IMETHODIMP
   713 RDFXMLDataSourceImpl::Move(nsIRDFResource* aOldSource,
   714                            nsIRDFResource* aNewSource,
   715                            nsIRDFResource* aProperty,
   716                            nsIRDFNode* aTarget)
   717 {
   718     nsresult rv;
   720     if (IsLoading() || mIsWritable) {
   721         rv = mInner->Move(aOldSource, aNewSource, aProperty, aTarget);
   722         if (!IsLoading() && rv == NS_RDF_ASSERTION_ACCEPTED)
   723             mIsDirty = true;
   724     }
   725     else {
   726         rv = NS_RDF_ASSERTION_REJECTED;
   727     }
   729     return rv;
   730 }
   733 nsresult
   734 RDFXMLDataSourceImpl::rdfXMLFlush(nsIURI *aURI)
   735 {
   737     nsresult rv;
   739     {
   740         // Quick and dirty check to see if we're in XPCOM shutdown. If
   741         // we are, we're screwed: it's too late to serialize because
   742         // many of the services that we'll need to acquire to properly
   743         // write the file will be unaquirable.
   744         NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
   745         nsCOMPtr<nsIRDFService> dummy = do_GetService(kRDFServiceCID, &rv);
   746         if (NS_FAILED(rv)) {
   747             NS_WARNING("unable to Flush() dirty datasource during XPCOM shutdown");
   748             return rv;
   749         }
   750     }
   752     // Is it a file? If so, we can write to it. Some day, it'd be nice
   753     // if we didn't care what kind of stream this was...
   754     nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aURI);
   756     if (fileURL) {
   757         nsCOMPtr<nsIFile> file;
   758         fileURL->GetFile(getter_AddRefs(file));
   759         if (file) {
   760             // get a safe output stream, so we don't clobber the datasource file unless
   761             // all the writes succeeded.
   762             nsCOMPtr<nsIOutputStream> out;
   763             rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(out),
   764                                                  file,
   765                                                  PR_WRONLY | PR_CREATE_FILE,
   766                                                  /*octal*/ 0666,
   767                                                  0);
   768             if (NS_FAILED(rv)) return rv;
   770             nsCOMPtr<nsIOutputStream> bufferedOut;
   771             rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOut), out, 4096);
   772             if (NS_FAILED(rv)) return rv;
   774             rv = Serialize(bufferedOut);
   775             if (NS_FAILED(rv)) return rv;
   777             // All went ok. Maybe except for problems in Write(), but the stream detects
   778             // that for us
   779             nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(bufferedOut, &rv);
   780             if (NS_FAILED(rv)) return rv;
   782             rv = safeStream->Finish();
   783             if (NS_FAILED(rv)) {
   784                 NS_WARNING("failed to save datasource file! possible dataloss");
   785                 return rv;
   786             }
   787         }
   788     }
   790     return NS_OK;
   791 }
   794 NS_IMETHODIMP
   795 RDFXMLDataSourceImpl::FlushTo(const char *aURI)
   796 {
   797     NS_PRECONDITION(aURI != nullptr, "not initialized");
   798     if (!aURI)
   799         return NS_ERROR_NULL_POINTER;
   801     // XXX this is a hack: any "file:" URI is considered writable. All
   802     // others are considered read-only.
   803     if ((PL_strncmp(aURI, kFileURIPrefix, sizeof(kFileURIPrefix) - 1) != 0) &&
   804         (PL_strncmp(aURI, kResourceURIPrefix, sizeof(kResourceURIPrefix) - 1) != 0))
   805     {
   806         return NS_ERROR_ILLEGAL_VALUE;
   807     }
   809     nsCOMPtr<nsIURI>  url;
   810     nsresult rv = NS_NewURI(getter_AddRefs(url), aURI);
   811     if (NS_FAILED(rv))
   812       return rv;
   813     rv = rdfXMLFlush(url);
   814     return rv;
   815 }
   818 NS_IMETHODIMP
   819 RDFXMLDataSourceImpl::Flush(void)
   820 {
   821     if (!mIsWritable || !mIsDirty)
   822         return NS_OK;
   824     // while it is not fatal if mURL is not set,
   825     // indicate failure since we can't flush back to an unknown origin
   826     if (! mURL)
   827         return NS_ERROR_NOT_INITIALIZED;
   829 #ifdef PR_LOGGING
   830     nsAutoCString spec;
   831     mURL->GetSpec(spec);
   832     PR_LOG(gLog, PR_LOG_NOTICE,
   833            ("rdfxml[%p] flush(%s)", this, spec.get()));
   834 #endif
   836     nsresult rv;
   837     if (NS_SUCCEEDED(rv = rdfXMLFlush(mURL)))
   838     {
   839       mIsDirty = false;
   840     }
   841     return rv;
   842 }
   845 //----------------------------------------------------------------------
   846 //
   847 // nsIRDFXMLDataSource methods
   848 //
   850 NS_IMETHODIMP
   851 RDFXMLDataSourceImpl::GetReadOnly(bool* aIsReadOnly)
   852 {
   853     *aIsReadOnly = !mIsWritable;
   854     return NS_OK;
   855 }
   858 NS_IMETHODIMP
   859 RDFXMLDataSourceImpl::SetReadOnly(bool aIsReadOnly)
   860 {
   861     if (mIsWritable && aIsReadOnly)
   862         mIsWritable = false;
   864     return NS_OK;
   865 }
   867 // nsIChannelEventSink
   869 // This code is copied from nsSameOriginChecker::OnChannelRedirect. See
   870 // bug 475940 on providing this code in a shared location.
   871 NS_IMETHODIMP
   872 RDFXMLDataSourceImpl::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
   873                                              nsIChannel *aNewChannel,
   874                                              uint32_t aFlags,
   875                                              nsIAsyncVerifyRedirectCallback *cb)
   876 {
   877     NS_PRECONDITION(aNewChannel, "Redirecting to null channel?");
   879     nsresult rv;
   880     nsCOMPtr<nsIScriptSecurityManager> secMan =
   881         do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
   882     NS_ENSURE_SUCCESS(rv, rv);
   884     nsCOMPtr<nsIPrincipal> oldPrincipal;
   885     secMan->GetChannelPrincipal(aOldChannel, getter_AddRefs(oldPrincipal));
   887     nsCOMPtr<nsIURI> newURI;
   888     aNewChannel->GetURI(getter_AddRefs(newURI));
   889     nsCOMPtr<nsIURI> newOriginalURI;
   890     aNewChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
   892     NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI);
   894     rv = oldPrincipal->CheckMayLoad(newURI, false, false);
   895     if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
   896         rv = oldPrincipal->CheckMayLoad(newOriginalURI, false, false);
   897     }
   899     if (NS_FAILED(rv))
   900         return rv;
   902     cb->OnRedirectVerifyCallback(NS_OK);
   903     return NS_OK;
   904 }
   906 NS_IMETHODIMP
   907 RDFXMLDataSourceImpl::Refresh(bool aBlocking)
   908 {
   909 #ifdef PR_LOGGING
   910     nsAutoCString spec;
   911     if (mURL) {
   912         mURL->GetSpec(spec);
   913     }
   914     PR_LOG(gLog, PR_LOG_NOTICE,
   915            ("rdfxml[%p] refresh(%s) %sblocking", this, spec.get(), (aBlocking ? "" : "non")));
   916 #endif
   918     // If an asynchronous load is already pending, then just let it do
   919     // the honors.
   920     if (IsLoading()) {
   921         PR_LOG(gLog, PR_LOG_NOTICE,
   922                ("rdfxml[%p] refresh(%s) a load was pending", this, spec.get()));
   924         if (aBlocking) {
   925             NS_WARNING("blocking load requested when async load pending");
   926             return NS_ERROR_FAILURE;
   927         }
   928         else {
   929             return NS_OK;
   930         }
   931     }
   933     if (! mURL)
   934         return NS_ERROR_FAILURE;
   935     nsCOMPtr<nsIRDFXMLParser> parser = do_CreateInstance("@mozilla.org/rdf/xml-parser;1");
   936     if (! parser)
   937         return NS_ERROR_FAILURE;
   939     nsresult rv = parser->ParseAsync(this, mURL, getter_AddRefs(mListener));
   940     if (NS_FAILED(rv)) return rv;
   942     if (aBlocking) {
   943         rv = BlockingParse(mURL, this);
   945         mListener = nullptr; // release the parser
   947         if (NS_FAILED(rv)) return rv;
   948     }
   949     else {
   950         // Null LoadGroup ?
   951         rv = NS_OpenURI(this, nullptr, mURL, nullptr, nullptr, this);
   952         if (NS_FAILED(rv)) return rv;
   954         // So we don't try to issue two asynchronous loads at once.
   955         mLoadState = eLoadState_Pending;
   956     }
   958     return NS_OK;
   959 }
   961 NS_IMETHODIMP
   962 RDFXMLDataSourceImpl::BeginLoad(void)
   963 {
   964 #ifdef PR_LOGGING
   965     nsAutoCString spec;
   966     if (mURL) {
   967         mURL->GetSpec(spec);
   968     }
   969     PR_LOG(gLog, PR_LOG_NOTICE,
   970            ("rdfxml[%p] begin-load(%s)", this, spec.get()));
   971 #endif
   973     mLoadState = eLoadState_Loading;
   974     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         nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
   980         if (obs) {
   981             obs->OnBeginLoad(this);
   982         }
   983     }
   984     return NS_OK;
   985 }
   987 NS_IMETHODIMP
   988 RDFXMLDataSourceImpl::Interrupt(void)
   989 {
   990 #ifdef PR_LOGGING
   991     nsAutoCString spec;
   992     if (mURL) {
   993         mURL->GetSpec(spec);
   994     }
   995     PR_LOG(gLog, PR_LOG_NOTICE,
   996            ("rdfxml[%p] interrupt(%s)", this, spec.get()));
   997 #endif
   999     for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
  1000         // Make sure to hold a strong reference to the observer so
  1001         // that it doesn't go away in this call if it removes itself
  1002         // as an observer
  1003         nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
  1005         if (obs) {
  1006             obs->OnInterrupt(this);
  1009     return NS_OK;
  1012 NS_IMETHODIMP
  1013 RDFXMLDataSourceImpl::Resume(void)
  1015 #ifdef PR_LOGGING
  1016     nsAutoCString spec;
  1017     if (mURL) {
  1018         mURL->GetSpec(spec);
  1020     PR_LOG(gLog, PR_LOG_NOTICE,
  1021            ("rdfxml[%p] resume(%s)", this, spec.get()));
  1022 #endif
  1024     for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
  1025         // Make sure to hold a strong reference to the observer so
  1026         // that it doesn't go away in this call if it removes itself
  1027         // as an observer
  1028         nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
  1030         if (obs) {
  1031             obs->OnResume(this);
  1034     return NS_OK;
  1037 NS_IMETHODIMP
  1038 RDFXMLDataSourceImpl::EndLoad(void)
  1040 #ifdef PR_LOGGING
  1041     nsAutoCString spec;
  1042     if (mURL) {
  1043         mURL->GetSpec(spec);
  1045     PR_LOG(gLog, PR_LOG_NOTICE,
  1046            ("rdfxml[%p] end-load(%s)", this, spec.get()));
  1047 #endif
  1049     mLoadState = eLoadState_Loaded;
  1051     // Clear out any unmarked assertions from the datasource.
  1052     nsCOMPtr<nsIRDFPurgeableDataSource> gcable = do_QueryInterface(mInner);
  1053     if (gcable) {
  1054         gcable->Sweep();
  1057     // Notify load observers
  1058     for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
  1059         // Make sure to hold a strong reference to the observer so
  1060         // that it doesn't go away in this call if it removes itself
  1061         // as an observer
  1062         nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
  1064         if (obs) {
  1065             obs->OnEndLoad(this);
  1068     return NS_OK;
  1071 NS_IMETHODIMP
  1072 RDFXMLDataSourceImpl::AddNameSpace(nsIAtom* aPrefix, const nsString& aURI)
  1074     mNameSpaces.Put(aURI, aPrefix);
  1075     return NS_OK;
  1079 NS_IMETHODIMP
  1080 RDFXMLDataSourceImpl::AddXMLSinkObserver(nsIRDFXMLSinkObserver* aObserver)
  1082     if (! aObserver)
  1083         return NS_ERROR_NULL_POINTER;
  1085     mObservers.AppendObject(aObserver);
  1086     return NS_OK;
  1089 NS_IMETHODIMP
  1090 RDFXMLDataSourceImpl::RemoveXMLSinkObserver(nsIRDFXMLSinkObserver* aObserver)
  1092     if (! aObserver)
  1093         return NS_ERROR_NULL_POINTER;
  1095     mObservers.RemoveObject(aObserver);
  1097     return NS_OK;
  1101 //----------------------------------------------------------------------
  1102 //
  1103 // nsIRequestObserver
  1104 //
  1106 NS_IMETHODIMP
  1107 RDFXMLDataSourceImpl::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
  1109     return mListener->OnStartRequest(request, ctxt);
  1112 NS_IMETHODIMP
  1113 RDFXMLDataSourceImpl::OnStopRequest(nsIRequest *request,
  1114                                     nsISupports *ctxt,
  1115                                     nsresult status)
  1117     if (NS_FAILED(status)) {
  1118         for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
  1119             // Make sure to hold a strong reference to the observer so
  1120             // that it doesn't go away in this call if it removes
  1121             // itself as an observer
  1122             nsCOMPtr<nsIRDFXMLSinkObserver> obs = mObservers[i];
  1124             if (obs) {
  1125                 obs->OnError(this, status, nullptr);
  1130     nsresult rv;
  1131     rv = mListener->OnStopRequest(request, ctxt, status);
  1133     mListener = nullptr; // release the parser
  1135     return rv;
  1138 //----------------------------------------------------------------------
  1139 //
  1140 // nsIStreamListener
  1141 //
  1143 NS_IMETHODIMP
  1144 RDFXMLDataSourceImpl::OnDataAvailable(nsIRequest *request,
  1145                                       nsISupports *ctxt,
  1146                                       nsIInputStream *inStr,
  1147                                       uint64_t sourceOffset,
  1148                                       uint32_t count)
  1150     return mListener->OnDataAvailable(request, ctxt, inStr, sourceOffset, count);
  1153 //----------------------------------------------------------------------
  1154 //
  1155 // nsIRDFXMLSource
  1156 //
  1158 NS_IMETHODIMP
  1159 RDFXMLDataSourceImpl::Serialize(nsIOutputStream* aStream)
  1161     nsresult rv;
  1162     nsCOMPtr<nsIRDFXMLSerializer> serializer
  1163         = do_CreateInstance("@mozilla.org/rdf/xml-serializer;1", &rv);
  1165     if (! serializer)
  1166         return rv;
  1168     rv = serializer->Init(this);
  1169     if (NS_FAILED(rv)) return rv;
  1171     // Add any namespace information that we picked up when reading
  1172     // the RDF/XML
  1173     nsNameSpaceMap::const_iterator last = mNameSpaces.last();
  1174     for (nsNameSpaceMap::const_iterator iter = mNameSpaces.first();
  1175          iter != last; ++iter) {
  1176         // We might wanna change nsIRDFXMLSerializer to nsACString and
  1177         // use a heap allocated buffer here in the future.
  1178         NS_ConvertUTF8toUTF16 uri(iter->mURI);
  1179         serializer->AddNameSpace(iter->mPrefix, uri);
  1182     // Serialize!
  1183     nsCOMPtr<nsIRDFXMLSource> source = do_QueryInterface(serializer);
  1184     if (! source)
  1185         return NS_ERROR_FAILURE;
  1187     return source->Serialize(aStream);

mercurial