1 /* 2 * Copyright 2010 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Christophe Huriaux, c.huriaux@gmail.com 7 */ 8 9 10 #include <ctype.h> 11 #include <string.h> 12 #include <new> 13 14 #include <String.h> 15 #include <HttpHeaders.h> 16 17 using namespace BPrivate::Network; 18 19 20 // #pragma mark -- BHttpHeader 21 22 23 BHttpHeader::BHttpHeader() 24 : 25 fName(), 26 fValue(), 27 fRawHeader(), 28 fRawHeaderValid(true) 29 { 30 } 31 32 33 BHttpHeader::BHttpHeader(const char* string) 34 : 35 fRawHeaderValid(true) 36 { 37 SetHeader(string); 38 } 39 40 41 BHttpHeader::BHttpHeader(const char* name, const char* value) 42 : 43 fRawHeaderValid(false) 44 { 45 SetName(name); 46 SetValue(value); 47 } 48 49 50 BHttpHeader::BHttpHeader(const BHttpHeader& copy) 51 : 52 fName(copy.fName), 53 fValue(copy.fValue), 54 fRawHeaderValid(false) 55 { 56 } 57 58 59 void 60 BHttpHeader::SetName(const char* name) 61 { 62 fRawHeaderValid = false; 63 fName = name; 64 fName.Trim().CapitalizeEachWord(); 65 } 66 67 68 void 69 BHttpHeader::SetValue(const char* value) 70 { 71 fRawHeaderValid = false; 72 fValue = value; 73 fValue.Trim(); 74 } 75 76 77 bool 78 BHttpHeader::SetHeader(const char* string) 79 { 80 fRawHeaderValid = false; 81 fName.Truncate(0); 82 fValue.Truncate(0); 83 84 const char* separator = strchr(string, ':'); 85 86 if (separator == NULL) 87 return false; 88 89 fName.SetTo(string, separator - string); 90 fName.Trim().CapitalizeEachWord(); 91 SetValue(separator + 1); 92 return true; 93 } 94 95 96 const char* 97 BHttpHeader::Name() const 98 { 99 return fName.String(); 100 } 101 102 103 const char* 104 BHttpHeader::Value() const 105 { 106 return fValue.String(); 107 } 108 109 110 const char* 111 BHttpHeader::Header() const 112 { 113 if (!fRawHeaderValid) { 114 fRawHeaderValid = true; 115 116 fRawHeader.Truncate(0); 117 fRawHeader << fName << ": " << fValue; 118 } 119 120 return fRawHeader.String(); 121 } 122 123 124 bool 125 BHttpHeader::NameIs(const char* name) const 126 { 127 return fName == BString(name).Trim().CapitalizeEachWord(); 128 } 129 130 131 BHttpHeader& 132 BHttpHeader::operator=(const BHttpHeader& other) 133 { 134 fName = other.fName; 135 fValue = other.fValue; 136 fRawHeaderValid = false; 137 138 return *this; 139 } 140 141 142 // #pragma mark -- BHttpHeaders 143 144 145 BHttpHeaders::BHttpHeaders() 146 : 147 fHeaderList() 148 { 149 } 150 151 152 BHttpHeaders::BHttpHeaders(const BHttpHeaders& other) 153 : 154 fHeaderList() 155 { 156 *this = other; 157 } 158 159 160 BHttpHeaders::~BHttpHeaders() 161 { 162 _EraseData(); 163 } 164 165 166 // #pragma mark Header access 167 168 169 const char* 170 BHttpHeaders::HeaderValue(const char* name) const 171 { 172 for (int32 i = 0; i < fHeaderList.CountItems(); i++) { 173 BHttpHeader* header 174 = reinterpret_cast<BHttpHeader*>(fHeaderList.ItemAtFast(i)); 175 176 if (header->NameIs(name)) 177 return header->Value(); 178 } 179 180 return NULL; 181 } 182 183 184 BHttpHeader& 185 BHttpHeaders::HeaderAt(int32 index) const 186 { 187 //! Note: index _must_ be in-bounds 188 BHttpHeader* header 189 = reinterpret_cast<BHttpHeader*>(fHeaderList.ItemAtFast(index)); 190 191 return *header; 192 } 193 194 195 // #pragma mark Header count 196 197 198 int32 199 BHttpHeaders::CountHeaders() const 200 { 201 return fHeaderList.CountItems(); 202 } 203 204 205 // #pragma Header tests 206 207 208 int32 209 BHttpHeaders::HasHeader(const char* name) const 210 { 211 for (int32 i = 0; i < fHeaderList.CountItems(); i++) { 212 BHttpHeader* header 213 = reinterpret_cast<BHttpHeader*>(fHeaderList.ItemAt(i)); 214 215 if (header->NameIs(name)) 216 return i; 217 } 218 219 return -1; 220 } 221 222 223 // #pragma mark Header add/replace 224 225 226 bool 227 BHttpHeaders::AddHeader(const char* line) 228 { 229 return _AddOrDeleteHeader(new(std::nothrow) BHttpHeader(line)); 230 } 231 232 233 bool 234 BHttpHeaders::AddHeader(const char* name, const char* value) 235 { 236 return _AddOrDeleteHeader(new(std::nothrow) BHttpHeader(name, value)); 237 } 238 239 240 bool 241 BHttpHeaders::AddHeader(const char* name, int32 value) 242 { 243 BString strValue; 244 strValue << value; 245 246 return AddHeader(name, strValue); 247 } 248 249 250 // #pragma mark Archiving 251 252 253 void 254 BHttpHeaders::PopulateFromArchive(BMessage* archive) 255 { 256 Clear(); 257 258 int32 index = 0; 259 char* nameFound; 260 for (;;) { 261 if (archive->GetInfo(B_STRING_TYPE, index, &nameFound, NULL) != B_OK) 262 return; 263 264 BString value = archive->FindString(nameFound); 265 AddHeader(nameFound, value); 266 267 index++; 268 } 269 } 270 271 272 void 273 BHttpHeaders::Archive(BMessage* message) const 274 { 275 int32 count = CountHeaders(); 276 277 for (int32 i = 0; i < count; i++) { 278 BHttpHeader& header = HeaderAt(i); 279 message->AddString(header.Name(), header.Value()); 280 } 281 } 282 283 284 // #pragma mark Header deletion 285 286 287 void 288 BHttpHeaders::Clear() 289 { 290 _EraseData(); 291 fHeaderList.MakeEmpty(); 292 } 293 294 295 // #pragma mark Overloaded operators 296 297 298 BHttpHeaders& 299 BHttpHeaders::operator=(const BHttpHeaders& other) 300 { 301 if (&other == this) 302 return *this; 303 304 Clear(); 305 306 for (int32 i = 0; i < other.CountHeaders(); i++) 307 AddHeader(other.HeaderAt(i).Name(), other.HeaderAt(i).Value()); 308 309 return *this; 310 } 311 312 313 BHttpHeader& 314 BHttpHeaders::operator[](int32 index) const 315 { 316 //! Note: Index _must_ be in-bounds 317 BHttpHeader* header 318 = reinterpret_cast<BHttpHeader*>(fHeaderList.ItemAtFast(index)); 319 320 return *header; 321 } 322 323 324 const char* 325 BHttpHeaders::operator[](const char* name) const 326 { 327 return HeaderValue(name); 328 } 329 330 331 void 332 BHttpHeaders::_EraseData() 333 { 334 // Free allocated data; 335 for (int32 i = 0; i < fHeaderList.CountItems(); i++) { 336 BHttpHeader* header 337 = reinterpret_cast<BHttpHeader*>(fHeaderList.ItemAtFast(i)); 338 339 delete header; 340 } 341 } 342 343 344 bool 345 BHttpHeaders::_AddOrDeleteHeader(BHttpHeader* header) 346 { 347 if (header != NULL) { 348 if (fHeaderList.AddItem(header)) 349 return true; 350 delete header; 351 } 352 return false; 353 } 354