|
1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 // System includes |
|
17 #include <e32std.h> |
|
18 #include <http/thttptable.h> |
|
19 #include <upnp/tupnptable.h> |
|
20 |
|
21 // Local includes |
|
22 #include "CHeaderField.h" |
|
23 #include "CHeaders.h" |
|
24 #include "rhttpheaders.h" |
|
25 #include "tupnpmessagepanic.h" |
|
26 |
|
27 |
|
28 CHeaders* CHeaders::NewL(CHeaderCodec& aCodec) |
|
29 { |
|
30 CHeaders* me = new(ELeave)CHeaders(aCodec); |
|
31 return me; |
|
32 } |
|
33 |
|
34 CHeaders::~CHeaders() |
|
35 { |
|
36 PurgeFields(); |
|
37 iFields.Close(); |
|
38 } |
|
39 |
|
40 RHTTPHeaders CHeaders::Handle() |
|
41 { |
|
42 RHTTPHeaders handle; |
|
43 handle.iImplementation = this; |
|
44 return handle; |
|
45 } |
|
46 |
|
47 |
|
48 // create or append a field part for the named field and assigned value |
|
49 void CHeaders::SetFieldL(RStringF aFieldName, THTTPHdrVal aFieldValue) |
|
50 { |
|
51 CHeaderField& field = CreateOrLookupFieldL(aFieldName); |
|
52 |
|
53 // Create a part for the value supplied |
|
54 CHeaderFieldPart* part = CHeaderFieldPart::NewL(aFieldValue); |
|
55 CleanupStack::PushL(part); |
|
56 field.AddPartL(part); |
|
57 CleanupStack::Pop(part); |
|
58 } |
|
59 |
|
60 // create or append a field part with parameter, for the specified field, parameter and associated values |
|
61 void CHeaders::SetFieldL(RStringF aFieldName, THTTPHdrVal aFieldValue, |
|
62 RStringF aParamName, THTTPHdrVal aParamValue) |
|
63 { |
|
64 CHeaderField& field = CreateOrLookupFieldL(aFieldName); |
|
65 |
|
66 // Check whether a part with the supplied value already exists, if so then the API semantics are that |
|
67 // an additional parameter should be set on that part. Otherwise a new part will be created. |
|
68 THeaderFieldPartIter iter = field.PartsL(); |
|
69 iter.First(); |
|
70 CHeaderFieldPart* part = NULL; |
|
71 while (!iter.AtEnd()) |
|
72 { |
|
73 const CHeaderFieldPart* pt = iter(); |
|
74 if (pt->Value() == aFieldValue) |
|
75 part = CONST_CAST(CHeaderFieldPart*, pt); |
|
76 ++iter; |
|
77 } |
|
78 |
|
79 // Create a part only if the match didn't occur |
|
80 if (!part) |
|
81 { |
|
82 part = CHeaderFieldPart::NewL(aFieldValue); |
|
83 CleanupStack::PushL(part); |
|
84 field.AddPartL(part); |
|
85 CleanupStack::Pop(part); |
|
86 } |
|
87 |
|
88 // Create a parameter for the value supplied |
|
89 CHeaderFieldParam* param = CHeaderFieldParam::NewL(aParamName, aParamValue); |
|
90 CleanupStack::PushL(param); |
|
91 part->AddParamL(param); |
|
92 CleanupStack::Pop(param); |
|
93 } |
|
94 |
|
95 // Set a named field in the header to contain the supplied Raw data. Any existing header field of |
|
96 // this name will be lost. |
|
97 void CHeaders::SetRawFieldL(RStringF aFieldName, const TDesC8& aRawFieldData, const TDesC8& aFieldSeparator) |
|
98 { |
|
99 // See if field exists |
|
100 TInt idx = LocateFieldName(aFieldName); |
|
101 |
|
102 if (idx == KErrNotFound) |
|
103 { |
|
104 // create a new one using the field name |
|
105 CHeaderField* hdr = CHeaderField::NewL(aFieldName, *this, aRawFieldData); |
|
106 CleanupStack::PushL(hdr); |
|
107 DoInsertInNameOrderL(hdr, aFieldName); |
|
108 CleanupStack::Pop(hdr); |
|
109 } |
|
110 else |
|
111 { |
|
112 CHeaderField* field = iFields[idx].iField; |
|
113 TPtrC8 originalRawData; |
|
114 field->RawDataL(originalRawData); |
|
115 |
|
116 // add the new raw data to the existing field using the aFieldSeparator param as a separator |
|
117 HBufC8* newRawDataBuf = HBufC8::NewLC(originalRawData.Length() + aFieldSeparator.Length() + aRawFieldData.Length()); |
|
118 TPtr8 newRawDataPtr = newRawDataBuf->Des(); |
|
119 newRawDataPtr.Append(originalRawData); |
|
120 newRawDataPtr.Append(aFieldSeparator); |
|
121 newRawDataPtr.Append(aRawFieldData); |
|
122 field->BeginRawDataL(); |
|
123 field->WriteRawDataL(*newRawDataBuf); |
|
124 field->CommitRawData(); |
|
125 CleanupStack::PopAndDestroy(newRawDataBuf); |
|
126 } |
|
127 } |
|
128 |
|
129 // Remove, entirely, the named header field from the header collection. All its parts and |
|
130 // associated parameters (where they exist) are also removed |
|
131 TInt CHeaders::RemoveField(RStringF aFieldName) |
|
132 { |
|
133 // Locate the name first - give up straight away if the field isn't found |
|
134 TInt idx = LocateFieldName(aFieldName); |
|
135 if (idx < 0) |
|
136 return idx; |
|
137 |
|
138 __ASSERT_DEBUG(idx < iFields.Count(), TUPnPMessagePanic::Panic(TUPnPMessagePanic::EHeaderFieldMissing)); |
|
139 // destroy the header field |
|
140 CHeaderField* field = iFields[idx].iField; |
|
141 iFields.Remove(idx); |
|
142 delete field; |
|
143 |
|
144 return KErrNone; |
|
145 } |
|
146 |
|
147 TInt CHeaders::RemoveFieldPartL(RStringF aFieldName, TInt aIndex) |
|
148 { |
|
149 TInt idx = LocateFieldName(aFieldName); |
|
150 if (idx == KErrNotFound) |
|
151 return idx; |
|
152 |
|
153 CHeaderField* field = iFields[idx].iField; |
|
154 field->RemovePartL(aIndex); |
|
155 |
|
156 if (field->NumPartsL() == 0) |
|
157 { |
|
158 iFields.Remove(idx); |
|
159 delete field; |
|
160 } |
|
161 return KErrNone; |
|
162 } |
|
163 |
|
164 void CHeaders::RemoveAllFields() |
|
165 { |
|
166 PurgeFields(); |
|
167 iFields.Reset(); |
|
168 } |
|
169 |
|
170 // Obtain the number of parts in the named header field's value, Simple headers are created with a single part |
|
171 // following one call to SetFieldL. Subsequent calls to SetFieldL create additional parts with the field exists |
|
172 // already |
|
173 TInt CHeaders::FieldPartsL(RStringF aFieldName) const |
|
174 { |
|
175 TInt idx = LocateFieldName(aFieldName); |
|
176 if (idx == KErrNotFound) |
|
177 return 0; |
|
178 |
|
179 CHeaderField* field = iFields[idx].iField; |
|
180 return field->NumPartsL(); |
|
181 } |
|
182 |
|
183 // Obtain the named header field's value. Optionally, the index of a part within the field |
|
184 // may be specified. Parts are indexed from zero |
|
185 TInt CHeaders::GetField(RStringF aFieldName, TInt aPartIdx, THTTPHdrVal& aHeaderValue) const |
|
186 { |
|
187 TInt error = KErrNone; |
|
188 CHeaderFieldPart* part = NULL; |
|
189 TRAPD(err, part = GetFieldPartL(aFieldName, aPartIdx)); |
|
190 if (err) |
|
191 return err; |
|
192 |
|
193 if (part) |
|
194 aHeaderValue = part->Value(); |
|
195 else |
|
196 error = KErrNotFound; |
|
197 return error; |
|
198 } |
|
199 |
|
200 // Obtain the raw representation of the named header field's value. |
|
201 TInt CHeaders::GetRawField(RStringF aFieldName, TPtrC8& aRawFieldData) const |
|
202 { |
|
203 TInt idx = LocateFieldName(aFieldName); |
|
204 if (idx < 0) |
|
205 return idx; |
|
206 CHeaderField* field = iFields[idx].iField; |
|
207 TRAPD(err,field->RawDataL(aRawFieldData)); |
|
208 |
|
209 if (err == KErrNone) |
|
210 { |
|
211 TInt newLinePos = aRawFieldData.Locate('\n'); |
|
212 if (newLinePos != KErrNotFound) |
|
213 { |
|
214 aRawFieldData.Set(aRawFieldData.Left(newLinePos)); |
|
215 } |
|
216 } |
|
217 |
|
218 return err; |
|
219 } |
|
220 |
|
221 |
|
222 // Obtain the value of a named parameter, associated with the named header field. An optional index to a part |
|
223 // within the header field may be supplied, if not it is assumed that it is the first part |
|
224 THTTPHdrVal CHeaders::GetParam(RStringF aFieldName, RStringF aParamName, |
|
225 THTTPHdrVal& aValue, TInt aPartIdx) const |
|
226 { |
|
227 CHeaderFieldParam* param = GetFieldParameter(aFieldName, aParamName, aPartIdx); |
|
228 if (param == NULL) |
|
229 return KErrNotFound; |
|
230 aValue = param->Value(); |
|
231 return 0; |
|
232 } |
|
233 |
|
234 // Set a param, overwriting one if it exists |
|
235 void CHeaders::SetParamL(RStringF aFieldName, RStringF aParamName,THTTPHdrVal aParamValue, TInt aPartIdx) |
|
236 { |
|
237 // Locate the name first |
|
238 TInt idx = LocateFieldName(aFieldName); |
|
239 User::LeaveIfError(idx); |
|
240 CHeaderField* field = iFields[idx].iField; |
|
241 CHeaderFieldPart* part = field->PartL(aPartIdx); |
|
242 CHeaderFieldParam* param = CHeaderFieldParam::NewL(aParamName, aParamValue); |
|
243 CleanupStack::PushL(param); |
|
244 part->AddParamL(param); |
|
245 CleanupStack::Pop(param); |
|
246 } |
|
247 |
|
248 |
|
249 // create an iterator initialised for this header collection |
|
250 THTTPHdrFieldIter CHeaders::Fields() const |
|
251 { |
|
252 return THTTPHdrFieldIter(this); |
|
253 } |
|
254 |
|
255 // Obtain the index in the CHeaderField/RStringF arrays for the named header |
|
256 TInt CHeaders::LocateFieldName(RStringF aHeaderName) const |
|
257 { |
|
258 // Locate the name first in the array of field names |
|
259 const TInt count = iFields.Count(); |
|
260 for (TInt ii = 0; ii < count; ++ii) |
|
261 { |
|
262 if (iFields[ii].iFieldName == aHeaderName) |
|
263 return ii; |
|
264 } |
|
265 return KErrNotFound; |
|
266 } |
|
267 |
|
268 // Check if a named header field exists. If so, return it. If not, create it. |
|
269 CHeaderField& CHeaders::CreateOrLookupFieldL(RStringF aFieldName) |
|
270 { |
|
271 // Locate the name first |
|
272 TInt idx = LocateFieldName(aFieldName); |
|
273 |
|
274 // If the header was found, return it. If no header matched, create |
|
275 // one for that field name |
|
276 CHeaderField* found = NULL; |
|
277 if (idx != KErrNotFound) |
|
278 { |
|
279 found = iFields[idx].iField; |
|
280 } |
|
281 else |
|
282 { |
|
283 CHeaderField* hdr = CHeaderField::NewL(aFieldName, *this); |
|
284 CleanupStack::PushL(hdr); |
|
285 DoInsertInNameOrderL(hdr, aFieldName); |
|
286 CleanupStack::Pop(hdr); |
|
287 found = hdr; |
|
288 } |
|
289 return *found; |
|
290 } |
|
291 |
|
292 // Get the indexed part of the named field, if it exists |
|
293 CHeaderFieldPart* CHeaders::GetFieldPartL(RStringF aFieldName, TInt aPartIdx) const |
|
294 { |
|
295 // check the field really exists |
|
296 TInt idx = LocateFieldName(aFieldName); |
|
297 User::LeaveIfError(idx); |
|
298 |
|
299 CHeaderField* field = iFields[idx].iField; |
|
300 CHeaderFieldPart* part = field->PartL(aPartIdx); |
|
301 return part; |
|
302 } |
|
303 |
|
304 // Get the named parameter from the named field, if it exists |
|
305 CHeaderFieldParam* CHeaders::GetFieldParameter(RStringF aFieldName, RStringF aParamName, TInt aPartIdx) const |
|
306 { |
|
307 // get the part and look up the named parameter |
|
308 CHeaderFieldPart* part = NULL; |
|
309 TRAPD(err, part = GetFieldPartL(aFieldName, aPartIdx)); |
|
310 if (part && !err) |
|
311 return part->Parameter(aParamName); |
|
312 |
|
313 if (err == KErrNotFound) |
|
314 return NULL; |
|
315 else |
|
316 { |
|
317 // find out what circumstances this might occur in. non-existent field is fine; |
|
318 // however if GetFieldPartL left then there might be a decoding error that should |
|
319 // be reported somehow. |
|
320 __DEBUGGER(); |
|
321 return NULL; |
|
322 } |
|
323 } |
|
324 |
|
325 |
|
326 void CHeaders::DoInsertInNameOrderL(CHeaderField* aHeader, RStringF aHeaderName) |
|
327 { |
|
328 THeaderFieldNamePair field; |
|
329 field.iFieldName = aHeaderName; |
|
330 field.iField = aHeader; |
|
331 TLinearOrder<THeaderFieldNamePair> sortKey(THeaderFieldNamePair::CompareFieldNames); |
|
332 User::LeaveIfError(iFields.InsertInOrder(field,sortKey)); |
|
333 } |
|
334 |
|
335 |
|
336 TInt CHeaders::THeaderFieldNamePair::CompareFieldNames(const THeaderFieldNamePair& aField1, |
|
337 const THeaderFieldNamePair& aField2) |
|
338 { |
|
339 TInt val1 = KErrNone; |
|
340 TInt val2 = KErrNone; |
|
341 |
|
342 RStringF header1 = aField1.iFieldName; |
|
343 RStringPool pool1 = aField1.iFieldName.Pool(); |
|
344 |
|
345 RStringF nts1 = pool1.StringF(UPnP::ENTS, TUPnPTable::Table()); |
|
346 RStringF nt1 = pool1.StringF(UPnP::ENT, TUPnPTable::Table()); |
|
347 RStringF usn1 = pool1.StringF(UPnP::EUSN, TUPnPTable::Table()); |
|
348 RStringF mx1 = pool1.StringF(UPnP::EMX, TUPnPTable::Table()); |
|
349 RStringF st1 = pool1.StringF(UPnP::EST, TUPnPTable::Table()); |
|
350 RStringF timeout1 = pool1.StringF(UPnP::ETimeout, TUPnPTable::Table()); |
|
351 RStringF seq1 = pool1.StringF(UPnP::ESEQ, TUPnPTable::Table()); |
|
352 RStringF man1 = pool1.StringF(UPnP::EMAN, TUPnPTable::Table()); |
|
353 RStringF soapaction1 = pool1.StringF(UPnP::ESoapAction, TUPnPTable::Table()); |
|
354 RStringF ext1 = pool1.StringF(UPnP::EExt, TUPnPTable::Table()); |
|
355 RStringF sid1 = pool1.StringF(UPnP::ESID, TUPnPTable::Table()); |
|
356 RStringF callback1 = pool1.StringF(UPnP::ECallback, TUPnPTable::Table()); |
|
357 |
|
358 RStringF header2 = aField2.iFieldName; |
|
359 RStringPool pool2 = aField2.iFieldName.Pool(); |
|
360 |
|
361 RStringF nts2 = pool2.StringF(UPnP::ENTS, TUPnPTable::Table()); |
|
362 RStringF nt2 = pool2.StringF(UPnP::ENT, TUPnPTable::Table()); |
|
363 RStringF usn2 = pool2.StringF(UPnP::EUSN, TUPnPTable::Table()); |
|
364 RStringF mx2 = pool2.StringF(UPnP::EMX, TUPnPTable::Table()); |
|
365 RStringF st2 = pool2.StringF(UPnP::EST, TUPnPTable::Table()); |
|
366 RStringF timeout2 = pool2.StringF(UPnP::ETimeout, TUPnPTable::Table()); |
|
367 RStringF seq2 = pool2.StringF(UPnP::ESEQ, TUPnPTable::Table()); |
|
368 RStringF man2 = pool2.StringF(UPnP::EMAN, TUPnPTable::Table()); |
|
369 RStringF soapaction2 = pool2.StringF(UPnP::ESoapAction, TUPnPTable::Table()); |
|
370 RStringF ext2 = pool2.StringF(UPnP::EExt, TUPnPTable::Table()); |
|
371 RStringF sid2 = pool2.StringF(UPnP::ESID, TUPnPTable::Table()); |
|
372 RStringF callback2 = pool2.StringF(UPnP::ECallback, TUPnPTable::Table()); |
|
373 |
|
374 if( |
|
375 ((header1.DesC().Compare(nts1.DesC()) == 0)||(header1.DesC().Compare(nt1.DesC()) == 0)|| |
|
376 (header1.DesC().Compare(usn1.DesC()) == 0)||(header1.DesC().Compare(mx1.DesC()) == 0)|| |
|
377 (header1.DesC().Compare(st1.DesC()) == 0)||(header1.DesC().Compare(timeout1.DesC()) == 0)|| |
|
378 (header1.DesC().Compare(seq1.DesC()) == 0)||(header1.DesC().Compare(man1.DesC()) == 0)|| |
|
379 (header1.DesC().Compare(soapaction1.DesC()) == 0)||(header1.DesC().Compare(ext1.DesC()) == 0)|| |
|
380 (header1.DesC().Compare(sid1.DesC()) == 0)||(header1.DesC().Compare(callback1.DesC()) == 0))&& |
|
381 ((header2.DesC().Compare(nts2.DesC()) == 0)||(header2.DesC().Compare(nt2.DesC()) == 0)|| |
|
382 (header2.DesC().Compare(usn2.DesC()) == 0)||(header2.DesC().Compare(mx2.DesC()) == 0)|| |
|
383 (header2.DesC().Compare(st2.DesC()) == 0)||(header2.DesC().Compare(timeout2.DesC()) == 0)|| |
|
384 (header2.DesC().Compare(seq2.DesC()) == 0)||(header1.DesC().Compare(man2.DesC()) == 0)|| |
|
385 (header2.DesC().Compare(soapaction2.DesC()) == 0)||(header2.DesC().Compare(ext2.DesC()) == 0)|| |
|
386 (header2.DesC().Compare(sid2.DesC()) == 0)||(header2.DesC().Compare(callback2.DesC()) == 0)) |
|
387 ) |
|
388 |
|
389 { |
|
390 val1 = aField1.iFieldName.Index(TUPnPTable::Table()); |
|
391 val2 = aField2.iFieldName.Index(TUPnPTable::Table()); |
|
392 } |
|
393 else |
|
394 { |
|
395 val1 = aField1.iFieldName.Index(THTTPTable::Table()); |
|
396 val2 = aField2.iFieldName.Index(THTTPTable::Table()); |
|
397 } |
|
398 |
|
399 if (val1 != KErrNotFound && val2 != KErrNotFound) |
|
400 return val1 - val2; |
|
401 else if (val1 != KErrNotFound) |
|
402 return -1; |
|
403 else if (val2 != KErrNotFound) |
|
404 return 1; |
|
405 else |
|
406 return aField1.iFieldName.DesC().Ptr() - |
|
407 aField2.iFieldName.DesC().Ptr(); |
|
408 } |
|
409 |
|
410 |
|
411 void CHeaders::PurgeFields() |
|
412 { |
|
413 const TInt count = iFields.Count(); |
|
414 for (TInt ii = 0; ii< count; ++ii) |
|
415 { |
|
416 delete iFields[ii].iField; |
|
417 } |
|
418 } |
|
419 |