1/* 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25// 26// headermap - represent Internet-standard headers 27// 28#include "headermap.h" 29#include <ctype.h> 30#include <assert.h> 31 32using namespace std; 33 34namespace Security { 35 36 37// 38// Given a constant text string, extract the leading substring up to 'end' (or \0), 39// canonicalize its case, and store the result for use. 40// 41HeaderMap::CanonicalKey::CanonicalKey(const char *key, char end) 42{ 43 assert(key && key[0]); // non-empty 44 mValue[0] = toupper(key[0]); 45 for (unsigned int n = 1; n < sizeof(mValue) - 1; n++) { 46 if (key[n] == end) { 47 mValue[n] = '\0'; 48 return; 49 } 50 mValue[n] = tolower(key[n]); 51 } 52 // overflow -- truncate? throw? dynamic allocation? seppuko? :-) 53 assert(false); 54} 55 56 57// 58// Add an entry 59// 60void HeaderMap::add(const char *key, const char *value) 61{ 62 add(CanonicalKey(key), value); 63} 64 65 66// 67// Given a standard form (Key: value), add its value to the headermap 68// 69void HeaderMap::add(const char *form) 70{ 71 while (*form && isspace(*form)) 72 form++; 73 if (const char *colon = strchr(form, ':')) { 74 CanonicalKey key(form, ':'); 75 const char *value = colon + 1; 76 while (*value && isspace(*value)) 77 value++; 78 add(key, value); 79 } else { 80 // ignore this 81 //@@@ signal an error? how? how bad? 82 } 83} 84 85 86// 87// Internal add method, given a canonicalized key 88// 89void HeaderMap::add(const CanonicalKey &key, const char *value) 90{ 91 Map::iterator it = mMap.find(key); 92 if (it == mMap.end()) 93 mMap[key] = value; 94 else 95 merge(key, mMap[key], value); 96} 97 98 99// 100// Locate an entry in a headermap. 101// Find returns NULL if not found; [] creates a new entry if needed and returns 102// a reference to the value, in good STL tradition. 103// 104const char *HeaderMap::find(const char *key, const char *defaultValue) const 105{ 106 Map::const_iterator it = mMap.find(CanonicalKey(key)); 107 return (it == mMap.end()) ? defaultValue : it->second.c_str(); 108} 109 110string &HeaderMap::operator[] (const char *key) 111{ 112 return mMap[CanonicalKey(key)]; 113} 114 115 116// 117// The default implementation of merge throws out the old contents and replaces 118// them with the new. 119// 120void HeaderMap::merge(string key, string &old, string newValue) 121{ 122 old = newValue; 123} 124 125 126// 127// Collect the entire contents into a single string 128// Note that this is NOT exactly what was passed in; certain canonicalizations have 129// been done; fields are reordered; and duplicate-header fields have been coalesced. 130//@@@ size could be pre-calculated (running counter). 131// 132string HeaderMap::collect(const char *lineEnding) const 133{ 134 string value; 135 for (Map::const_iterator it = mMap.begin(); it != mMap.end(); it++) 136 value += it->first + ": " + it->second + lineEnding; 137 return value; 138} 139 140size_t HeaderMap::collectLength(const char *lineEnding) const 141{ 142 size_t size = 0; 143 size_t sepLength = strlen(lineEnding); 144 for (Map::const_iterator it = mMap.begin(); it != mMap.end(); it++) 145 size += it->first.length() + 2 + it->second.length() + sepLength; 146 return size; 147} 148 149 150} // end namespace Security 151