Back to index

lightning-sunbird  0.9+nobinonly
txURIUtils.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is TransforMiiX XSLT processor code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * The MITRE Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Keith Visco <kvisco@ziplink.net> (Original Author)
00024  *   Larry Fitzpatrick, OpenText <lef@opentext.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "txURIUtils.h"
00041 
00042 #ifndef TX_EXE
00043 #include "nsNetUtil.h"
00044 #include "nsIAttribute.h"
00045 #include "nsIScriptSecurityManager.h"
00046 #include "nsIDocument.h"
00047 #include "nsIDOMDocument.h"
00048 #include "nsIContent.h"
00049 #include "nsIPrincipal.h"
00050 #include "nsINodeInfo.h"
00051 #endif
00052 
00058 #ifdef TX_EXE
00059 //- Constants -/
00060 
00061 const char   URIUtils::HREF_PATH_SEP  = '/';
00062 
00067 void
00068 txParsedURL::init(const nsAFlatString& aSpec)
00069 {
00070     mPath.Truncate();
00071     mName.Truncate();
00072     mRef.Truncate();
00073     PRUint32 specLength = aSpec.Length();
00074     if (!specLength) {
00075         return;
00076     }
00077     const PRUnichar* start = aSpec.get();
00078     const PRUnichar* end = start + specLength;
00079     const PRUnichar* c = end - 1;
00080 
00081     // check for #ref
00082     for (; c >= start; --c) {
00083         if (*c == '#') {
00084             // we could eventually unescape this, too.
00085             mRef = Substring(c + 1, end);
00086             end = c;
00087             --c;
00088             if (c == start) {
00089                 // we're done,
00090                 return;
00091             }
00092             break;
00093         }
00094     }
00095     for (c = end - 1; c >= start; --c) {
00096         if (*c == '/') {
00097             mName = Substring(c + 1, end);
00098             mPath = Substring(start, c + 1);
00099             return;
00100         }
00101     }
00102     mName = Substring(start, end);
00103 }
00104 
00105 void
00106 txParsedURL::resolve(const txParsedURL& aRef, txParsedURL& aDest)
00107 {
00108     /*
00109      * No handling of absolute URLs now.
00110      * These aren't really URLs yet, anyway, but paths with refs
00111      */
00112     aDest.mPath = mPath + aRef.mPath;
00113 
00114     if (aRef.mName.IsEmpty() && aRef.mPath.IsEmpty()) {
00115         // the relative URL is just a fragment identifier
00116         aDest.mName = mName;
00117         if (aRef.mRef.IsEmpty()) {
00118             // and not even that, keep the base ref
00119             aDest.mRef = mRef;
00120             return;
00121         }
00122         aDest.mRef = aRef.mRef;
00123         return;
00124     }
00125     aDest.mName = aRef.mName;
00126     aDest.mRef = aRef.mRef;
00127 }
00128 
00137 istream* URIUtils::getInputStream(const nsAString& href, nsAString& errMsg)
00138 {
00139     return new ifstream(NS_LossyConvertUCS2toASCII(href).get(), ios::in);
00140 } //-- getInputStream
00141 
00146 void URIUtils::getDocumentBase(const nsAFlatString& href, nsAString& dest)
00147 {
00148     if (href.IsEmpty()) {
00149         return;
00150     }
00151 
00152     nsAFlatString::const_char_iterator temp;
00153     href.BeginReading(temp);
00154     PRUint32 iter = href.Length();
00155     while (iter > 0) {
00156         if (temp[--iter] == HREF_PATH_SEP) {
00157             dest.Append(Substring(href, 0, iter));
00158             break;
00159         }
00160     }
00161 }
00162 #endif
00163 
00169 void URIUtils::resolveHref(const nsAString& href, const nsAString& base,
00170                            nsAString& dest) {
00171     if (base.IsEmpty()) {
00172         dest.Append(href);
00173         return;
00174     }
00175     if (href.IsEmpty()) {
00176         dest.Append(base);
00177         return;
00178     }
00179 
00180 #ifndef TX_EXE
00181     nsCOMPtr<nsIURI> pURL;
00182     nsAutoString resultHref;
00183     nsresult result = NS_NewURI(getter_AddRefs(pURL), base);
00184     if (NS_SUCCEEDED(result)) {
00185         NS_MakeAbsoluteURI(resultHref, href, pURL);
00186         dest.Append(resultHref);
00187     }
00188 #else
00189     nsAutoString documentBase;
00190     getDocumentBase(PromiseFlatString(base), documentBase);
00191 
00192     //-- join document base + href
00193     if (!documentBase.IsEmpty()) {
00194         dest.Append(documentBase);
00195         if (documentBase.CharAt(documentBase.Length()-1) != HREF_PATH_SEP)
00196             dest.Append(PRUnichar(HREF_PATH_SEP));
00197     }
00198     dest.Append(href);
00199 
00200 #endif
00201 } //-- resolveHref
00202 
00203 #ifndef TX_EXE
00204 
00205 nsIScriptSecurityManager *gTxSecurityManager = 0;
00206 
00207 // static
00208 PRBool URIUtils::CanCallerAccess(nsIDOMNode *aNode)
00209 {
00210     if (!gTxSecurityManager) {
00211         // No security manager available, let any calls go through...
00212 
00213         return PR_TRUE;
00214     }
00215 
00216     nsCOMPtr<nsIPrincipal> subjectPrincipal;
00217     gTxSecurityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
00218 
00219     if (!subjectPrincipal) {
00220         // we're running as system, grant access to the node.
00221 
00222         return PR_TRUE;
00223     }
00224 
00225     // Check whether the subject principal is the system principal.
00226     // For performance, we will avoid calling SubjectPrincipalIsChrome()
00227     // since it calls GetSubjectPrincipal() which causes us to walk
00228     // the JS frame stack.  We already did that above, so just get the
00229     // system principal from the security manager, and do a raw comparison.
00230     nsCOMPtr<nsIPrincipal> systemPrincipal;
00231     gTxSecurityManager->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
00232 
00233     if (subjectPrincipal == systemPrincipal) {
00234         // we're running as system, grant access to the node.
00235 
00236         return PR_TRUE;
00237     }
00238 
00239     // Make sure that this is a real node. We do this by first QI'ing to
00240     // nsIContent (which is important performance wise) and if that QI
00241     // fails we QI to nsIDocument. If both those QI's fail we won't let
00242     // the caller access this unknown node.
00243     nsIPrincipal *principal = nsnull;
00244     nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
00245     nsCOMPtr<nsIAttribute> attr;
00246     nsCOMPtr<nsIDocument> doc;
00247 
00248     if (!content) {
00249         doc = do_QueryInterface(aNode);
00250 
00251         if (!doc) {
00252             attr = do_QueryInterface(aNode);
00253             if (!attr) {
00254                 // aNode is not a nsIContent, a nsIAttribute or a nsIDocument,
00255                 // something weird is going on...
00256 
00257                 NS_ERROR("aNode is not a nsIContent, a nsIAttribute or a nsIDocument!");
00258 
00259                 return PR_FALSE;
00260             }
00261         }
00262     }
00263 
00264     if (!doc) {
00265         nsCOMPtr<nsIDOMDocument> domDoc;
00266         aNode->GetOwnerDocument(getter_AddRefs(domDoc));
00267         if (!domDoc) {
00268             nsINodeInfo *ni;
00269             if (content) {
00270                 ni = content->GetNodeInfo();
00271             }
00272             else {
00273                 ni = attr->NodeInfo();
00274             }
00275 
00276             if (!ni) {
00277                 // aNode is not part of a document, let any caller access it.
00278 
00279                 return PR_TRUE;
00280             }
00281 
00282             principal = ni->GetDocumentPrincipal();
00283             if (!principal) {
00284               // we can't get to the principal so we'll give up and give the
00285               // caller access
00286 
00287               return PR_TRUE;
00288             }
00289         }
00290         else {
00291             doc = do_QueryInterface(domDoc);
00292             NS_ASSERTION(doc, "QI to nsIDocument failed");
00293         }
00294     }
00295 
00296     if (!principal) {
00297         principal = doc->GetPrincipal();
00298     }
00299 
00300     if (!principal) {
00301         // We can't get hold of the principal for this node. This should happen
00302         // very rarely, like for textnodes out of the tree and <option>s created
00303         // using 'new Option'.
00304 
00305         return PR_TRUE;
00306     }
00307 
00308     if (principal == systemPrincipal) {
00309         // We already know the subject is NOT systemPrincipal, no point calling
00310         // CheckSameOriginPrincipal since we know they don't match.
00311 
00312         return PR_FALSE;
00313     }
00314 
00315     // Ask the securitymanager if we have "UniversalBrowserRead"
00316     PRBool caps = PR_FALSE;
00317     nsresult rv =
00318         gTxSecurityManager->IsCapabilityEnabled("UniversalBrowserRead",
00319                                                 &caps);
00320     NS_ENSURE_SUCCESS(rv, PR_FALSE);
00321     if (caps) {
00322         return PR_TRUE;
00323     }
00324 
00325     rv = gTxSecurityManager->CheckSameOriginPrincipal(subjectPrincipal,
00326                                                       principal);
00327 
00328     return NS_SUCCEEDED(rv);
00329 }
00330 
00331 // static
00332 void
00333 URIUtils::ResetWithSource(nsIDocument *aNewDoc, nsIDOMNode *aSourceNode)
00334 {
00335     if (!aSourceNode) {
00336         // XXXbz passing nsnull as the first arg to Reset is illegal
00337         aNewDoc->Reset(nsnull, nsnull);
00338         return;
00339     }
00340 
00341     nsCOMPtr<nsIDocument> sourceDoc = do_QueryInterface(aSourceNode);
00342     if (!sourceDoc) {
00343         nsCOMPtr<nsIDOMDocument> sourceDOMDocument;
00344         aSourceNode->GetOwnerDocument(getter_AddRefs(sourceDOMDocument));
00345         sourceDoc = do_QueryInterface(sourceDOMDocument);
00346     }
00347     if (!sourceDoc) {
00348         NS_ASSERTION(0, "no source document found");
00349         // XXXbz passing nsnull as the first arg to Reset is illegal
00350         aNewDoc->Reset(nsnull, nsnull);
00351         return;
00352     }
00353 
00354     nsIPrincipal* sourcePrincipal = sourceDoc->GetPrincipal();
00355     if (!sourcePrincipal) {
00356         return;
00357     }
00358 
00359     // Copy the channel and loadgroup from the source document.
00360     nsCOMPtr<nsILoadGroup> loadGroup = sourceDoc->GetDocumentLoadGroup();
00361     nsCOMPtr<nsIChannel> channel = sourceDoc->GetChannel();
00362     if (!channel) {
00363         // Need to synthesize one
00364         if (NS_FAILED(NS_NewChannel(getter_AddRefs(channel),
00365                                     sourceDoc->GetDocumentURI(),
00366                                     nsnull,
00367                                     loadGroup))) {
00368             return;
00369         }
00370         channel->SetOwner(sourcePrincipal);
00371     }
00372     aNewDoc->Reset(channel, loadGroup);
00373     aNewDoc->SetPrincipal(sourcePrincipal);
00374     aNewDoc->SetBaseURI(sourceDoc->GetBaseURI());
00375 
00376     // Copy charset
00377     aNewDoc->SetDocumentCharacterSet(sourceDoc->GetDocumentCharacterSet());
00378     aNewDoc->SetDocumentCharacterSetSource(
00379           sourceDoc->GetDocumentCharacterSetSource());
00380 }
00381 
00382 #endif /* TX_EXE */