Back to index

lightning-sunbird  0.9+nobinonly
nsPolicyReference.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 the Platform for Privacy Preferences.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s): Harish Dhurvasula <harishd@netscape.com>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsPolicyReference.h"
00039 #include "nsNetUtil.h"
00040 #include "nsP3PUtils.h"
00041 #include "nsIDOMEventTarget.h"
00042 #include "nsIDOMElement.h"
00043 #include "nsIDOMNodeList.h"
00044 #include "nsIPolicyListener.h"
00045 
00046 #define CLEAN_ARRAY_AND_RETURN_IF_FAILED(_result, _array) \
00047  PR_BEGIN_MACRO                    \
00048  if(NS_FAILED(_result)) {          \
00049    nsP3PUtils::CleanArray(_array); \
00050    return _result;                 \
00051  }                                 \
00052  PR_END_MACRO
00053 
00054 static const char kWellKnownLocation[] = "/w3c/p3p.xml";
00055 static const char kW3C[] = "/w3c/";
00056 
00057 static nsresult
00058 RequestSucceeded(nsIXMLHttpRequest* aRequest, PRBool* aReturn)
00059 {
00060   NS_ENSURE_ARG_POINTER(aRequest);
00061 
00062   nsresult rv;
00063   nsCOMPtr<nsIChannel> channel;
00064   aRequest->GetChannel(getter_AddRefs(channel));
00065   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel, &rv));
00066   NS_ENSURE_TRUE(httpChannel, rv);
00067 
00068   return httpChannel->GetRequestSucceeded(aReturn);
00069 }
00070 
00071 NS_IMPL_ISUPPORTS4(nsPolicyReference,
00072                    nsIPolicyReference,
00073                    nsIPolicyTarget,
00074                    nsIDOMEventListener,
00075                    nsISupportsWeakReference)
00076 
00077 nsPolicyReference::nsPolicyReference() 
00078   : mFlags (0),
00079     mError (0)
00080 {
00081 }
00082 
00083 nsPolicyReference::~nsPolicyReference()
00084 {
00085 }
00086 
00087 NS_IMETHODIMP
00088 nsPolicyReference::Initialize(nsIURI* aMainURI)
00089 {
00090   NS_ENSURE_ARG_POINTER(aMainURI);
00091 
00092   mMainURI = aMainURI;
00093   mFlags = 0;
00094   mError = 0;
00095   return NS_OK;
00096 }
00097 
00098 NS_IMETHODIMP
00099 nsPolicyReference::Finalize() 
00100 {
00101   nsresult result = NS_OK;
00102   if (mXMLHttpRequest) { 
00103     nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(mXMLHttpRequest));
00104     if (target) {
00105       result = target->RemoveEventListener(NS_LITERAL_STRING("load"), this, PR_FALSE);
00106     }
00107   }
00108   return result;
00109 }
00110 
00111 NS_IMETHODIMP
00112 nsPolicyReference::HandleEvent(nsIDOMEvent  *aEvent) 
00113 {
00114   NS_ASSERTION(mXMLHttpRequest, "no xml http request");
00115 
00116   nsresult result = NS_OK;
00117   nsCOMPtr<nsIPolicyListener> listener(do_QueryReferent(mListener));
00118   NS_ENSURE_TRUE(listener, NS_ERROR_FAILURE);
00119 
00120   if (mXMLHttpRequest) {
00121     nsCOMPtr<nsIDOMDocument> document;
00122     if (mFlags & IS_MAIN_URI) {
00123       if (!mDocument) {
00124         mXMLHttpRequest->GetResponseXML(getter_AddRefs(mDocument));
00125         PRBool success;
00126         result = RequestSucceeded(mXMLHttpRequest, &success);
00127         if (NS_FAILED(result) || !success) {
00128           listener->NotifyPolicyLocation(0, POLICY_LOAD_FAILURE);
00129           return result;
00130         }
00131       }
00132       document = mDocument;
00133     }
00134     else {
00135       mXMLHttpRequest->GetResponseXML(getter_AddRefs(document));
00136       PRBool success;
00137       result = RequestSucceeded(mXMLHttpRequest, &success);
00138       if (NS_FAILED(result) || !success) {
00139         listener->NotifyPolicyLocation(0, POLICY_LOAD_FAILURE);
00140         return result;
00141       }
00142       if (mFlags & IS_LINKED_URI) {
00143         mDocument = document;
00144       }
00145     }
00146   
00147     nsXPIDLCString policyLocation;
00148     result = ProcessPolicyReferenceFile(document, getter_Copies(policyLocation));
00149       
00150     if (NS_SUCCEEDED(result)) {
00151       listener->NotifyPolicyLocation(policyLocation, mError);
00152     }
00153     else {
00154       listener->NotifyPolicyLocation(0, POLICY_LOAD_FAILURE);
00155     }
00156   }
00157 
00158   return result;
00159 }
00160 
00171 NS_IMETHODIMP
00172 nsPolicyReference::LoadPolicyReferenceFileFor(nsIURI* aURI,
00173                                               PRUint32 aFlag)
00174 {
00175 
00176   NS_ENSURE_ARG_POINTER(aURI);
00177 
00178   nsresult result = NS_OK;
00179   
00180   mFlags      = aFlag;
00181   mCurrentURI = aURI;
00182 
00183   if (mFlags & IS_MAIN_URI) {
00184     // Load policy reference file from the well known location.
00185     // well known location = /w3c/p3p.xml
00186     if (!mDocument) {
00187       nsXPIDLCString value;
00188       mMainURI->GetPrePath(value);
00189       value.AppendLiteral(kWellKnownLocation);
00190       result = Load(value);
00191     }
00192     else {
00193       // Policy reference document already exists.
00194       result = HandleEvent(0);
00195     }
00196   }
00197   else if (mFlags & IS_EMBEDDED_URI) {
00198     // The embedded uri's host is different from the main uri's host. 
00199     // Load the policy reference file from the embedded uri's 
00200     // well known location
00201     nsXPIDLCString value;
00202     mCurrentURI->GetPrePath(value);
00203     value.AppendLiteral(kWellKnownLocation);
00204     result = Load(value);
00205   }
00206   else if (mFlags & IS_LINKED_URI) {
00207     // Load policy referenced via html/xhtml LINK tag.
00208     mLinkedURI = aURI;
00209     nsXPIDLCString value;
00210     mLinkedURI->GetSpec(value);
00211     result = Load(value);
00212   }
00213  
00214   return result;
00215 }
00216 
00217 NS_IMETHODIMP
00218 nsPolicyReference::SetupPolicyListener(nsIPolicyListener* aListener)
00219 {
00220   NS_ENSURE_ARG_POINTER(aListener);
00221 
00222   mListener = do_GetWeakReference(aListener);
00223   return NS_OK;
00224 }
00225 
00226 nsresult
00227 nsPolicyReference::Load(const nsACString& aURI)
00228 {
00229   NS_ASSERTION(aURI.Length(), "no uri to load");
00230 
00231   nsresult result = NS_OK;
00232 
00233   if (!mXMLHttpRequest) {
00234     mXMLHttpRequest = do_CreateInstance(NS_XMLHTTPREQUEST_CONTRACTID, &result);
00235     NS_ENSURE_SUCCESS(result, result); 
00236     
00237     nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(mXMLHttpRequest, &result));
00238     NS_ENSURE_SUCCESS(result, result);
00239 
00240     target->AddEventListener(NS_LITERAL_STRING("load"), this, PR_FALSE);
00241   }
00242 
00243   const nsAString& empty = EmptyString();
00244   result = mXMLHttpRequest->OpenRequest(NS_LITERAL_CSTRING("GET"),
00245                                         aURI, PR_TRUE, empty, empty);
00246   NS_ENSURE_SUCCESS(result, result);
00247    
00248   mXMLHttpRequest->OverrideMimeType(NS_LITERAL_CSTRING("application/xml"));
00249 
00250   return mXMLHttpRequest->Send(nsnull);
00251 
00252 }
00253                         
00254 nsresult
00255 nsPolicyReference::ProcessPolicyReferenceFile(nsIDOMDocument* aDocument,
00256                                               char** aPolicyLocation)
00257 {
00258 
00259   NS_ENSURE_ARG_POINTER(aDocument);
00260   NS_ENSURE_ARG_POINTER(aPolicyLocation);
00261     
00262   nsCOMPtr<nsIDOMElement> domElement;
00263   aDocument->GetDocumentElement(getter_AddRefs(domElement));
00264 
00265   nsCOMPtr<nsIDOMNode> root(do_QueryInterface(domElement));
00266   NS_ENSURE_TRUE(root, NS_ERROR_UNEXPECTED);
00267 
00268   nsAutoString name;
00269   root->GetNodeName(name);
00270 
00271   nsresult result = NS_OK;
00272   
00273   // The root element MUST be META
00274   mError = name.EqualsLiteral("META") 
00275     ? POLICY_LOAD_SUCCESS : POLICY_SYNTAX_ERROR;
00276  
00277   if (mError != POLICY_LOAD_SUCCESS)
00278     return result;
00279   
00280   nsCOMPtr<nsIDOMNodeList> policyReferencesElement;
00281   aDocument->GetElementsByTagName(NS_LITERAL_STRING("POLICY-REFERENCES"), 
00282                                   getter_AddRefs(policyReferencesElement));
00283   NS_ENSURE_TRUE(policyReferencesElement, NS_ERROR_UNEXPECTED);
00284 
00285   PRUint32 count;
00286   policyReferencesElement->GetLength(&count);
00287 
00288   // There MUST be exactly |one| POLICY-REFERENCES element
00289   mError = (count == 1) ? POLICY_LOAD_SUCCESS : POLICY_SYNTAX_ERROR;
00290 
00291   if (mError != POLICY_LOAD_SUCCESS)
00292     return result;
00293 
00294   nsCOMPtr<nsIDOMNodeList> expiryElement;
00295   aDocument->GetElementsByTagName(NS_LITERAL_STRING("EXPIRY"), 
00296                                   getter_AddRefs(expiryElement));
00297 
00298   result = ProcessExpiryElement(expiryElement);
00299   NS_ENSURE_SUCCESS(result, result);
00300 
00301   if (mError != POLICY_LOAD_SUCCESS)
00302     return result;
00303 
00304   nsCOMPtr<nsIDOMNodeList> policyRefElement;
00305   aDocument->GetElementsByTagName(NS_LITERAL_STRING("POLICY-REF"), 
00306                                   getter_AddRefs(policyRefElement));
00307 
00308   nsAutoString policyLocation;
00309   result = ProcessPolicyRefElement(aDocument, policyRefElement, policyLocation);
00310   NS_ENSURE_SUCCESS(result, result);
00311       
00312   if (mError != POLICY_LOAD_SUCCESS || policyLocation.IsEmpty())
00313       return result;
00314 
00315   nsAutoString absURI;
00316   if (mFlags & IS_LINKED_URI) {
00317     result = NS_MakeAbsoluteURI(absURI, policyLocation,  mLinkedURI);
00318     NS_ENSURE_SUCCESS(result, result);
00319   }
00320   else {
00321     // Make sure that the fragment identifier belongs to the current host.
00322     if (policyLocation.First() == '#') {
00323       policyLocation = PromiseFlatString(NS_LITERAL_STRING("p3p.xml") + policyLocation);
00324     }
00325     if (mFlags & IS_MAIN_URI) {
00326       nsCOMPtr<nsIURI> tmpURI= mMainURI;
00327       tmpURI->SetPath(NS_LITERAL_CSTRING(kW3C));
00328       result = NS_MakeAbsoluteURI(absURI, policyLocation,  tmpURI);
00329       NS_ENSURE_SUCCESS(result, result);
00330     }
00331     else {
00332       // it is ok to do this because we won't be needing current uri beyond this.
00333       mCurrentURI->SetPath(NS_LITERAL_CSTRING(kW3C));
00334       result = NS_MakeAbsoluteURI(absURI, policyLocation,  mCurrentURI);
00335       NS_ENSURE_SUCCESS(result, result);
00336     }
00337   }
00338   *aPolicyLocation = ToNewCString(absURI);
00339   NS_ENSURE_TRUE(*aPolicyLocation, NS_ERROR_OUT_OF_MEMORY);
00340  
00341   return result;
00342 }
00343 
00344 nsresult
00345 nsPolicyReference::ProcessPolicyRefElement(nsIDOMDocument* aDocument, 
00346                                            nsIDOMNodeList* aNodeList, 
00347                                            nsAString& aPolicyLocation)
00348 {
00349   NS_ENSURE_ARG_POINTER(aDocument);
00350   NS_ENSURE_ARG_POINTER(aNodeList);
00351 
00352   PRUint32 count;
00353   aNodeList->GetLength(&count);
00354 
00355   nsAutoString element;
00356   for (PRUint32 i = 0; i < count; i++) {
00357     nsCOMPtr<nsIDOMNode> node;
00358     aNodeList->Item(i, getter_AddRefs(node));
00359     NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED);
00360     
00361     nsresult result = ProcessPolicyRefChildren(node);
00362     NS_ENSURE_SUCCESS(result, result);
00363 
00364     if (mError == POLICY_LOAD_SUCCESS) {
00365       return nsP3PUtils::GetAttributeValue(node, "about", aPolicyLocation);
00366     }
00367   }
00368 
00369   return NS_OK;
00370 }
00371 
00372 nsresult 
00373 nsPolicyReference::ProcessExpiryElement(nsIDOMNodeList* aNodeList)
00374 {
00375   NS_ENSURE_ARG_POINTER(aNodeList);
00376   
00377   PRUint32 count;
00378   aNodeList->GetLength(&count);
00379   if (count > 0) {
00380     nsCOMPtr<nsIDOMNode> node;
00381     aNodeList->Item(0, getter_AddRefs(node)); // There ought to be only one EXPIRY element
00382     NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED);
00383     
00384     nsAutoString date;
00385     nsP3PUtils::GetAttributeValue(node, "date", date); // absdate
00386     if (!date.IsEmpty()) {
00387       char* cdate = ToNewCString(date);
00388       NS_ENSURE_TRUE(*cdate, NS_ERROR_OUT_OF_MEMORY);
00389        
00390       PRTime prdate;
00391       if (PR_ParseTimeString(cdate, PR_TRUE, &prdate) == PR_SUCCESS) {
00392         if (prdate < PR_Now()) {
00393           mError = POLICY_LIFE_EXPIRED;
00394         }
00395       }
00396       nsMemory::Free(cdate);
00397     }
00398   }
00399 
00400   return NS_OK;
00401 }
00402 
00403 nsresult
00404 nsPolicyReference::ProcessPolicyRefChildren(nsIDOMNode* aNode)
00405 {
00406   NS_ENSURE_ARG_POINTER(aNode);
00407 
00408   nsresult result = NS_OK;
00409   // When INCLUDE elements are present in a POLICY-REF element, it means that
00410   // the policy specified in the about attribute of the POLICY-REF element applies to
00411   // all the URIs at the requested host corresponding to the local-URI(s) matched by
00412   // any of the INCLUDES, but not matched by an EXCLUDE. It is legal, but pointles,
00413   // to supply the EXCLUDE element without any INCLUDE lements; in that case, the
00414   // EXCLUDE element MUST be ignored.
00415 
00416   nsAutoVoidArray elements;
00417   nsXPIDLCString path;
00418   mCurrentURI->GetPath(path);
00419 
00420   nsP3PUtils::GetElementsByTagName(aNode, NS_LITERAL_STRING("INCLUDE"), elements);
00421   CLEAN_ARRAY_AND_RETURN_IF_FAILED(result, elements);
00422 
00423   if (elements.Count() == 0) {
00424     mError = POLICY_LOAD_FAILURE;
00425     return NS_OK; // INCLUDE elements not found so no need to check for EXCLUDE
00426   }
00427 
00428   PRBool pathIncluded = PR_FALSE;
00429   result = nsP3PUtils::DeterminePolicyScope(elements, path, &pathIncluded);
00430   CLEAN_ARRAY_AND_RETURN_IF_FAILED(result, elements);
00431 
00432   mError = pathIncluded ? POLICY_LOAD_SUCCESS : POLICY_LOAD_FAILURE;
00433   if (mError == POLICY_LOAD_SUCCESS) {
00434     result = 
00435       nsP3PUtils::GetElementsByTagName(aNode, NS_LITERAL_STRING("EXCLUDE"), elements);
00436     CLEAN_ARRAY_AND_RETURN_IF_FAILED(result, elements);
00437 
00438     PRBool pathExcluded = PR_FALSE;
00439     result = nsP3PUtils::DeterminePolicyScope(elements, path, &pathExcluded);
00440     mError = pathExcluded ? POLICY_LOAD_FAILURE : POLICY_LOAD_SUCCESS;
00441   }
00442   nsP3PUtils::CleanArray(elements);
00443   
00444   return result;
00445 }