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
BHttpHeader()23 BHttpHeader::BHttpHeader()
24 :
25 fName(),
26 fValue(),
27 fRawHeader(),
28 fRawHeaderValid(true)
29 {
30 }
31
32
BHttpHeader(const char * string)33 BHttpHeader::BHttpHeader(const char* string)
34 :
35 fRawHeaderValid(true)
36 {
37 SetHeader(string);
38 }
39
40
BHttpHeader(const char * name,const char * value)41 BHttpHeader::BHttpHeader(const char* name, const char* value)
42 :
43 fRawHeaderValid(false)
44 {
45 SetName(name);
46 SetValue(value);
47 }
48
49
BHttpHeader(const BHttpHeader & copy)50 BHttpHeader::BHttpHeader(const BHttpHeader& copy)
51 :
52 fName(copy.fName),
53 fValue(copy.fValue),
54 fRawHeaderValid(false)
55 {
56 }
57
58
59 void
SetName(const char * name)60 BHttpHeader::SetName(const char* name)
61 {
62 fRawHeaderValid = false;
63 fName = name;
64 fName.Trim().CapitalizeEachWord();
65 }
66
67
68 void
SetValue(const char * value)69 BHttpHeader::SetValue(const char* value)
70 {
71 fRawHeaderValid = false;
72 fValue = value;
73 fValue.Trim();
74 }
75
76
77 bool
SetHeader(const char * string)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*
Name() const97 BHttpHeader::Name() const
98 {
99 return fName.String();
100 }
101
102
103 const char*
Value() const104 BHttpHeader::Value() const
105 {
106 return fValue.String();
107 }
108
109
110 const char*
Header() const111 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
NameIs(const char * name) const125 BHttpHeader::NameIs(const char* name) const
126 {
127 return fName == BString(name).Trim().CapitalizeEachWord();
128 }
129
130
131 BHttpHeader&
operator =(const BHttpHeader & other)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
BHttpHeaders()145 BHttpHeaders::BHttpHeaders()
146 :
147 fHeaderList()
148 {
149 }
150
151
BHttpHeaders(const BHttpHeaders & other)152 BHttpHeaders::BHttpHeaders(const BHttpHeaders& other)
153 :
154 fHeaderList()
155 {
156 *this = other;
157 }
158
159
~BHttpHeaders()160 BHttpHeaders::~BHttpHeaders()
161 {
162 _EraseData();
163 }
164
165
166 // #pragma mark Header access
167
168
169 const char*
HeaderValue(const char * name) const170 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&
HeaderAt(int32 index) const185 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
CountHeaders() const199 BHttpHeaders::CountHeaders() const
200 {
201 return fHeaderList.CountItems();
202 }
203
204
205 // #pragma Header tests
206
207
208 int32
HasHeader(const char * name) const209 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
AddHeader(const char * line)227 BHttpHeaders::AddHeader(const char* line)
228 {
229 return _AddOrDeleteHeader(new(std::nothrow) BHttpHeader(line));
230 }
231
232
233 bool
AddHeader(const char * name,const char * value)234 BHttpHeaders::AddHeader(const char* name, const char* value)
235 {
236 return _AddOrDeleteHeader(new(std::nothrow) BHttpHeader(name, value));
237 }
238
239
240 bool
AddHeader(const char * name,int32 value)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
PopulateFromArchive(BMessage * archive)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
Archive(BMessage * message) const273 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
Clear()288 BHttpHeaders::Clear()
289 {
290 _EraseData();
291 fHeaderList.MakeEmpty();
292 }
293
294
295 // #pragma mark Overloaded operators
296
297
298 BHttpHeaders&
operator =(const BHttpHeaders & other)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&
operator [](int32 index) const314 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*
operator [](const char * name) const325 BHttpHeaders::operator[](const char* name) const
326 {
327 return HeaderValue(name);
328 }
329
330
331 void
_EraseData()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
_AddOrDeleteHeader(BHttpHeader * header)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