/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: NPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Netscape Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the NPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the NPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsP3PService.h" #include "nsCompactPolicy.h" #include "nsNetCID.h" #include "nsReadableUtils.h" // define an array of all compact policy tags #define CP_TOKEN(_token) #_token, static const char* kTokens[] = { #include "nsTokenList.h" }; #undef CP_TOKEN static nsHashtable* gTokenTable; static Tokens Lookup(const char* aTag) { Tokens rv = eToken_NULL; nsCStringKey key(aTag, -1, nsCStringKey::NEVER_OWN); void* val = (gTokenTable)? gTokenTable->Get(&key):0; if (val) { rv = Tokens(NS_PTR_TO_INT32(val)); } return rv; } static PRBool FindCompactPolicy(nsACString::const_iterator& aStart, nsACString::const_iterator& aEnd) { PRBool found = PR_FALSE; nsACString::const_iterator tmp = aEnd; if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("CP"), aStart, tmp)) { while (*tmp == ' ' && ++tmp != aEnd); // skip spaces if (tmp != aEnd && *tmp == '=') { while (++tmp != aEnd && *tmp == ' '); // skip spaces if (tmp != aEnd) { aStart = tmp; // Compact policy starts found = PR_TRUE; } } } return found; } static const PRInt32 MapTokenToConsent(const nsACString::const_iterator& aStart, const nsACString::const_iterator& aEnd) { PRInt32 rv = -1; if (aStart != aEnd) { PRInt32 len = Distance(aStart,aEnd); if (len > 2 && len < 5) { char token[5] = {0}; const char* begin = aStart.get(); memcpy(token,begin,3); eTokens id = Lookup(token); switch (id) { case eToken_TST: case eToken_NULL: // Token not in CP vocabulary! rv = NS_INVALID_POLICY; break; // Tokens that indicate collection of // Personally Identifiable Information // without consent. case eToken_FIN: case eToken_GOV: case eToken_ONL: case eToken_PHY: case eToken_UNI: rv = NS_NO_CONSENT; break; // Tokens that indicate collection of // Personally Identifiable Information // with opt-in, opt-out options. case eToken_CON: case eToken_DEL: case eToken_IVA: case eToken_IVD: case eToken_OTP: case eToken_OTR: case eToken_PUB: case eToken_SAM: case eToken_TEL: case eToken_UNR: { char attr = (len > 3)? *(begin+3):'\0'; rv = NS_NO_CONSENT; // Tokens with or without attribute 'a' if (attr == 'o') { rv = NS_IMPLICIT_CONSENT; } else if (attr == 'i') { rv = NS_EXPLICIT_CONSENT; } } break; default: rv = NS_NON_PII_TOKEN; break; } } else { rv = NS_INVALID_POLICY; } } return rv; } static const PRInt32 ParsePolicy(nsACString::const_iterator& aStart, nsACString::const_iterator& aEnd) { PRInt32 rv = NS_HAS_POLICY; if (aStart != aEnd) { // stip off the begining quote if (*aStart == '"' && ++aStart == aEnd) { return NS_NO_POLICY ; } nsACString::const_iterator tokenStart = aStart; while (aStart != aEnd) { if (*aStart != ' ' && *aStart != '"') { // quote ends compact policy ++aStart; } else { PRInt32 consent = MapTokenToConsent(tokenStart,aStart); if (consent == -1) { if (!(rv & NS_NO_CONSENT | NS_IMPLICIT_CONSENT | NS_EXPLICIT_CONSENT | NS_NON_PII_TOKEN)) { rv = NS_NO_POLICY; } break; } else if (consent == NS_INVALID_POLICY) { rv = NS_INVALID_POLICY; break; } else { rv |= consent; while (++aStart != aEnd && *aStart == ' '); // skip spaces tokenStart = aStart; } } } } NS_ASSERTION(rv > NS_HAS_POLICY,"compact policy error"); return rv; } /************************************* * nsCompactPolicy Implementation * *************************************/ nsCompactPolicy::nsCompactPolicy( ) { } nsCompactPolicy::~nsCompactPolicy( ) { } nsresult nsCompactPolicy::InitTokenTable(void) { gTokenTable = new nsHashtable(); NS_ENSURE_TRUE(gTokenTable, NS_ERROR_OUT_OF_MEMORY); for (PRInt32 i = 0; i < NS_CP_TOKEN_MAX; i++) { nsCStringKey key(kTokens[i], -1, nsCStringKey::NEVER_OWN); gTokenTable->Put(&key, (void*)(i+1)); } return NS_OK; } void nsCompactPolicy::DestroyTokenTable(void) { delete gTokenTable; } nsresult nsCompactPolicy::OnHeaderAvailable(const char* aP3PHeader, const char* aSpec) { NS_ENSURE_ARG_POINTER(aP3PHeader); NS_ENSURE_ARG_POINTER(aSpec); nsresult result = NS_OK; nsDependentCString header(aP3PHeader); nsACString::const_iterator begin, end; header.BeginReading(begin); header.EndReading(end); if (FindCompactPolicy(begin,end)) { PRInt32 consent = ParsePolicy(begin,end); nsCStringKey key(aSpec); mPolicyTable.Put(&key, NS_INT32_TO_PTR(consent)); } return result; } nsresult nsCompactPolicy::GetConsent(const char* aURI, PRInt32& aConsent) { NS_ENSURE_ARG_POINTER(aURI); nsresult result = NS_OK; nsCStringKey key(aURI, -1, nsCStringKey::NEVER_OWN); if (mPolicyTable.Exists(&key)) { aConsent = NS_PTR_TO_INT32(mPolicyTable.Get(&key)); } return result; }