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