Back to index

lightning-sunbird  0.9+nobinonly
nsCompactPolicy.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 "nsP3PService.h"
00039 #include "nsCompactPolicy.h"
00040 #include "nsNetCID.h"
00041 #include "nsReadableUtils.h"                             
00042 
00043 // define an array of all compact policy tags
00044 #define CP_TOKEN(_token) #_token,
00045 static const char* kTokens[] = {
00046 #include "nsTokenList.h"
00047 };
00048 #undef CP_TOKEN
00049 
00050 static nsHashtable* gTokenTable;
00051 
00052 static 
00053 Tokens Lookup(const char* aTag)
00054 {
00055   Tokens rv = eToken_NULL;
00056   
00057   nsCStringKey key(aTag, -1, nsCStringKey::NEVER_OWN);
00058 
00059   void* val = (gTokenTable)? gTokenTable->Get(&key):0;
00060   if (val) {
00061     rv = Tokens(NS_PTR_TO_INT32(val));
00062   }
00063 
00064   return rv;
00065 }
00066 
00067 static 
00068 PRBool FindCompactPolicy(nsACString::const_iterator& aStart,
00069                          nsACString::const_iterator& aEnd) {
00070   PRBool found = PR_FALSE;
00071   nsACString::const_iterator tmp = aEnd;
00072 
00073   if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("CP"), aStart, tmp)) {
00074     while (*tmp == ' ' && ++tmp != aEnd); // skip spaces
00075     
00076     if (tmp != aEnd && *tmp == '=') {
00077 
00078       while (++tmp != aEnd && *tmp == ' '); // skip spaces
00079       
00080       if (tmp != aEnd) {
00081         aStart = tmp; // Compact policy starts
00082         found = PR_TRUE;
00083       }
00084     }
00085   }
00086 
00087   return found;
00088 }
00089 
00090 static const
00091 PRInt32 MapTokenToConsent(const nsACString::const_iterator& aStart,
00092                           const nsACString::const_iterator& aEnd) 
00093 {
00094   PRInt32 rv = -1;
00095 
00096   if (aStart != aEnd) {
00097     PRInt32 len = Distance(aStart,aEnd);
00098     if (len > 2 && len < 5) {
00099       char  token[5] = {0};
00100       const char* begin = aStart.get();
00101       
00102       memcpy(token,begin,3);
00103      
00104       eTokens id = Lookup(token);
00105       switch (id) {
00106         case eToken_TST:
00107         case eToken_NULL: // Token not in CP vocabulary!
00108           rv = NS_INVALID_POLICY;
00109           break;
00110         // Tokens that indicate collection of
00111         // Personally Identifiable Information
00112         // without consent.
00113         case eToken_FIN: 
00114         case eToken_GOV:
00115         case eToken_ONL:
00116         case eToken_PHY:
00117         case eToken_UNI:
00118           rv = NS_PII_TOKEN;
00119           break;
00120         // Tokens that indicate collection of
00121         // Personally Identifiable Information 
00122         // with opt-in, opt-out options.
00123         case eToken_CON:
00124         case eToken_DEL:
00125         case eToken_IVA:
00126         case eToken_IVD:
00127         case eToken_OTP:
00128         case eToken_OTR:
00129         case eToken_PUB: 
00130         case eToken_SAM: 
00131         case eToken_TEL: 
00132         case eToken_UNR:
00133           {
00134             char attr = (len > 3)? *(begin+3):'\0';
00135             rv = NS_NO_CONSENT; // Tokens with or without attribute 'a'
00136             if (attr == 'o') {
00137               rv = NS_IMPLICIT_CONSENT;
00138             }
00139             else if (attr == 'i') {
00140               rv = NS_EXPLICIT_CONSENT;
00141             }
00142           }
00143           break;
00144         default:
00145           rv = NS_NON_PII_TOKEN;
00146           break;
00147       }
00148     }
00149     else {
00150       rv = NS_INVALID_POLICY;
00151     }
00152   }
00153   return rv;
00154 }
00155 
00156 static const
00157 PRInt32 ParsePolicy(nsACString::const_iterator& aStart,
00158                     nsACString::const_iterator& aEnd)
00159 {
00160   PRInt32 rv = NS_HAS_POLICY;
00161   
00162   if (aStart != aEnd) {
00163     // strip off the begining quote or apostrophe
00164     const char quoteChar = *aStart;
00165     if ((quoteChar == '"' || quoteChar == '\'') && ++aStart == aEnd) {
00166       return NS_NO_POLICY ;
00167     }
00168 
00169     nsACString::const_iterator tokenStart = aStart;
00170     while (aStart != aEnd) {
00171       if (*aStart != ' ' && *aStart != quoteChar) { 
00172         ++aStart;
00173       }
00174       else {
00175         PRInt32 consent = MapTokenToConsent(tokenStart,aStart);
00176 
00177         if (consent == -1) {
00178           if (!(rv & (NS_PII_TOKEN  |
00179                       NS_NO_CONSENT | 
00180                       NS_IMPLICIT_CONSENT | 
00181                       NS_EXPLICIT_CONSENT |  
00182                       NS_NON_PII_TOKEN))) {
00183             rv = NS_NO_POLICY;
00184           }
00185           break;
00186         }
00187         else if (consent == NS_INVALID_POLICY) {
00188           rv = NS_INVALID_POLICY;
00189           break;
00190         }
00191         else {
00192           rv |= consent;
00193           if (consent & NS_PII_TOKEN) {
00194             if (rv & NS_NO_CONSENT) {
00195               // PII is collected without consent.
00196               // No need to parse CP any further.
00197               break;
00198             }
00199           }
00200           else if (consent & NS_NO_CONSENT) {
00201             rv &= ~(NS_IMPLICIT_CONSENT | NS_EXPLICIT_CONSENT);
00202             if (rv & NS_PII_TOKEN) {
00203               // PII is collected without consent.
00204               // No need to parse CP any further.
00205               break;
00206             }
00207           }
00208           else if (consent & NS_IMPLICIT_CONSENT) {
00209             rv &= ~NS_EXPLICIT_CONSENT;
00210             if (rv & NS_NO_CONSENT) {
00211               rv &= ~NS_IMPLICIT_CONSENT;
00212             }
00213           }
00214           else if (consent & NS_EXPLICIT_CONSENT) {
00215             if (rv & (NS_NO_CONSENT | NS_IMPLICIT_CONSENT)) {
00216               rv &= ~NS_EXPLICIT_CONSENT;
00217             }
00218           }
00219           
00220           if (*aStart == quoteChar) {
00221             break; // done parsing CP
00222           }
00223          
00224           while (++aStart != aEnd && *aStart == ' '); // skip spaces
00225           tokenStart = aStart;
00226         }
00227       }
00228     }
00229 
00230     if (rv & NS_PII_TOKEN) {
00231       if (!(rv & (NS_NO_CONSENT | NS_IMPLICIT_CONSENT | NS_EXPLICIT_CONSENT))) {
00232         // CP did not contain any information about opt-in / opt-out
00233         rv = NS_NO_CONSENT; 
00234       }
00235     }
00236     else {
00237       // If a PII token is not present, in the CP, we can be sure
00238       // that no personally identifiable information is collected.
00239       if (rv & (NS_NO_CONSENT | NS_IMPLICIT_CONSENT | NS_EXPLICIT_CONSENT)) {
00240         rv = NS_NON_PII_TOKEN; // PII not collected.
00241       }
00242     }
00243   }
00244    
00245   NS_ASSERTION(rv > NS_HAS_POLICY,"compact policy error");
00246   return rv;
00247 }
00248 
00249 /*************************************
00250 * nsCompactPolicy Implementation *
00251 *************************************/
00252 
00253 nsCompactPolicy::nsCompactPolicy( ) {
00254 }
00255 
00256 nsCompactPolicy::~nsCompactPolicy( ) {
00257 }
00258 
00259 nsresult
00260 nsCompactPolicy::InitTokenTable(void) 
00261 {
00262   gTokenTable = new nsHashtable();
00263   NS_ENSURE_TRUE(gTokenTable, NS_ERROR_OUT_OF_MEMORY);
00264 
00265   for (PRInt32 i = 0; i < NS_CP_TOKEN_MAX; i++) {
00266     nsCStringKey key(kTokens[i], -1, nsCStringKey::NEVER_OWN);
00267     gTokenTable->Put(&key, (void*)(i+1));
00268   }
00269   return NS_OK;
00270 }
00271 
00272 void
00273 nsCompactPolicy::DestroyTokenTable(void) 
00274 {
00275   delete gTokenTable;
00276 }
00277 
00278 nsresult
00279 nsCompactPolicy::OnHeaderAvailable(const char* aP3PHeader,
00280                                    const char* aSpec)
00281 {
00282   NS_ENSURE_ARG_POINTER(aP3PHeader);
00283   NS_ENSURE_ARG_POINTER(aSpec);
00284 
00285   nsresult result = NS_OK;
00286     
00287   nsDependentCString header(aP3PHeader);
00288   nsACString::const_iterator begin, end;
00289 
00290   header.BeginReading(begin);
00291   header.EndReading(end);
00292 
00293   if (FindCompactPolicy(begin,end)) {
00294     nsCStringKey key(aSpec);
00295     if (!mPolicyTable.Exists(&key)) {
00296       PRInt32 consent =  ParsePolicy(begin,end);
00297       mPolicyTable.Put(&key, NS_INT32_TO_PTR(consent));
00298     }
00299   }
00300   
00301   return result;
00302 }
00303 
00304 nsresult
00305 nsCompactPolicy::GetConsent(const char* aURI,
00306                             PRInt32& aConsent)
00307 {
00308   NS_ENSURE_ARG_POINTER(aURI);
00309 
00310   nsresult result = NS_OK;
00311 
00312   nsCStringKey key(aURI, -1, nsCStringKey::NEVER_OWN);
00313   if (mPolicyTable.Exists(&key)) {
00314     aConsent = NS_PTR_TO_INT32(mPolicyTable.Get(&key));
00315   }
00316   
00317   return result;
00318 }
00319