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 17using namespace BPrivate::Network; 18 19 20// #pragma mark -- BHttpHeader 21 22 23BHttpHeader::BHttpHeader() 24 : 25 fName(), 26 fValue(), 27 fRawHeader(), 28 fRawHeaderValid(true) 29{ 30} 31 32 33BHttpHeader::BHttpHeader(const char* string) 34 : 35 fRawHeaderValid(true) 36{ 37 SetHeader(string); 38} 39 40 41BHttpHeader::BHttpHeader(const char* name, const char* value) 42 : 43 fRawHeaderValid(false) 44{ 45 SetName(name); 46 SetValue(value); 47} 48 49 50BHttpHeader::BHttpHeader(const BHttpHeader& copy) 51 : 52 fName(copy.fName), 53 fValue(copy.fValue), 54 fRawHeaderValid(false) 55{ 56} 57 58 59void 60BHttpHeader::SetName(const char* name) 61{ 62 fRawHeaderValid = false; 63 fName = name; 64 fName.Trim().CapitalizeEachWord(); 65} 66 67 68void 69BHttpHeader::SetValue(const char* value) 70{ 71 fRawHeaderValid = false; 72 fValue = value; 73 fValue.Trim(); 74} 75 76 77bool 78BHttpHeader::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 96const char* 97BHttpHeader::Name() const 98{ 99 return fName.String(); 100} 101 102 103const char* 104BHttpHeader::Value() const 105{ 106 return fValue.String(); 107} 108 109 110const char* 111BHttpHeader::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 124bool 125BHttpHeader::NameIs(const char* name) const 126{ 127 return fName == BString(name).Trim().CapitalizeEachWord(); 128} 129 130 131BHttpHeader& 132BHttpHeader::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 145BHttpHeaders::BHttpHeaders() 146 : 147 fHeaderList() 148{ 149} 150 151 152BHttpHeaders::BHttpHeaders(const BHttpHeaders& other) 153 : 154 fHeaderList() 155{ 156 *this = other; 157} 158 159 160BHttpHeaders::~BHttpHeaders() 161{ 162 _EraseData(); 163} 164 165 166// #pragma mark Header access 167 168 169const char* 170BHttpHeaders::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 184BHttpHeader& 185BHttpHeaders::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 198int32 199BHttpHeaders::CountHeaders() const 200{ 201 return fHeaderList.CountItems(); 202} 203 204 205// #pragma Header tests 206 207 208int32 209BHttpHeaders::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 226bool 227BHttpHeaders::AddHeader(const char* line) 228{ 229 return _AddOrDeleteHeader(new(std::nothrow) BHttpHeader(line)); 230} 231 232 233bool 234BHttpHeaders::AddHeader(const char* name, const char* value) 235{ 236 return _AddOrDeleteHeader(new(std::nothrow) BHttpHeader(name, value)); 237} 238 239 240bool 241BHttpHeaders::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 253void 254BHttpHeaders::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 272void 273BHttpHeaders::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 287void 288BHttpHeaders::Clear() 289{ 290 _EraseData(); 291 fHeaderList.MakeEmpty(); 292} 293 294 295// #pragma mark Overloaded operators 296 297 298BHttpHeaders& 299BHttpHeaders::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 313BHttpHeader& 314BHttpHeaders::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 324const char* 325BHttpHeaders::operator[](const char* name) const 326{ 327 return HeaderValue(name); 328} 329 330 331void 332BHttpHeaders::_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 344bool 345BHttpHeaders::_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