Coverage Report

Created: 2026-01-10 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/resiprocate/resip/stack/ParserCategory.cxx
Line
Count
Source
1
#if defined(HAVE_CONFIG_H)
2
#include "config.h"
3
#endif
4
5
#include "resip/stack/HeaderFieldValue.hxx"
6
#include "resip/stack/ParserCategory.hxx"
7
#include "rutil/ParseBuffer.hxx"
8
#include "resip/stack/SipMessage.hxx"
9
#include "rutil/DataStream.hxx"
10
#include "rutil/ParseBuffer.hxx"
11
#include "rutil/compat.hxx"
12
13
#include "resip/stack/UnknownParameter.hxx"
14
#include "resip/stack/ExtensionParameter.hxx"
15
16
#include <iostream>
17
#include "rutil/ResipAssert.h"
18
19
#include "rutil/Logger.hxx"
20
//#include "rutil/WinLeakCheck.hxx"  // not compatible with placement new used below
21
22
#define RESIPROCATE_SUBSYSTEM Subsystem::SIP
23
24
using namespace resip;
25
using namespace std;
26
27
const ParserCategory::ParameterTypeSet 
28
ParserCategory::EmptyParameterTypeSet; 
29
30
ParserCategory::ParserCategory(const HeaderFieldValue& headerFieldValue,
31
                               Headers::Type headerType,
32
                               PoolBase* pool)
33
72.5k
    : LazyParser(headerFieldValue),
34
72.5k
      mParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
35
72.5k
      mUnknownParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
36
72.5k
      mPool(pool),
37
72.5k
      mHeaderType(headerType)
38
72.5k
{
39
72.5k
}
40
41
ParserCategory::ParserCategory(const char* buf, 
42
                                 int length, 
43
                                 Headers::Type type,
44
                                 PoolBase* pool):
45
0
   LazyParser(buf, length),
46
0
   mParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
47
0
   mUnknownParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
48
0
   mPool(pool),
49
0
   mHeaderType(type)
50
0
{}
51
52
ParserCategory::ParserCategory(PoolBase* pool)
53
30.7k
   : LazyParser(),
54
30.7k
     mParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
55
30.7k
     mUnknownParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
56
30.7k
     mPool(pool),
57
30.7k
     mHeaderType(Headers::NONE)
58
30.7k
{
59
30.7k
}
60
61
ParserCategory::ParserCategory(const ParserCategory& rhs,
62
                               PoolBase* pool)
63
72.4k
   : LazyParser(rhs),
64
72.4k
     mParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
65
72.4k
     mUnknownParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
66
72.4k
     mPool(pool),
67
72.4k
     mHeaderType(rhs.mHeaderType)
68
72.4k
{
69
72.4k
   if (isParsed())
70
72.4k
   {
71
72.4k
      copyParametersFrom(rhs);
72
72.4k
   }
73
72.4k
}
74
75
ParserCategory&
76
ParserCategory::operator=(const ParserCategory& rhs)
77
5.53k
{
78
5.53k
   if (this != &rhs)
79
5.53k
   {
80
5.53k
      clear();
81
5.53k
      mHeaderType = rhs.mHeaderType;
82
5.53k
      LazyParser::operator=(rhs);
83
5.53k
      if (rhs.isParsed())
84
5.53k
      {
85
5.53k
         copyParametersFrom(rhs);
86
5.53k
      }
87
5.53k
   }
88
5.53k
   return *this;
89
5.53k
}
90
91
void
92
ParserCategory::clear()
93
181k
{
94
   //DebugLog(<<"ParserCategory::clear");
95
181k
   LazyParser::clear();
96
97
189k
   while(!mParameters.empty())
98
8.35k
   {
99
8.35k
      freeParameter(mParameters.back());
100
8.35k
      mParameters.pop_back();
101
8.35k
   }
102
103
232k
   while(!mUnknownParameters.empty())
104
51.5k
   {
105
51.5k
      freeParameter(mUnknownParameters.back());
106
51.5k
      mUnknownParameters.pop_back();
107
51.5k
   }
108
181k
}
109
110
void 
111
ParserCategory::copyParametersFrom(const ParserCategory& other)
112
77.9k
{
113
77.9k
   mParameters.reserve(other.mParameters.size());
114
77.9k
   mUnknownParameters.reserve(other.mUnknownParameters.size());
115
   
116
77.9k
   for (ParameterList::const_iterator it = other.mParameters.begin();
117
78.5k
        it != other.mParameters.end(); it++)
118
654
   {
119
654
      mParameters.push_back((*it)->clone());
120
654
   }
121
77.9k
   for (ParameterList::const_iterator it = other.mUnknownParameters.begin();
122
83.8k
        it != other.mUnknownParameters.end(); it++)
123
5.88k
   {
124
5.88k
      mUnknownParameters.push_back((*it)->clone());
125
5.88k
   }
126
77.9k
}
127
128
ParserCategory::~ParserCategory()
129
175k
{
130
175k
   clear();
131
175k
}
132
133
const Data&
134
ParserCategory::param(const ExtensionParameter& param) const
135
0
{
136
0
   checkParsed();
137
0
   Parameter* p = getParameterByData(param.getName());
138
0
   if (!p)
139
0
   {
140
0
      InfoLog(<< "Referenced an unknown parameter " << param.getName());
141
0
      throw Exception("Missing unknown parameter", __FILE__, __LINE__);
142
0
   }
143
0
   return static_cast<UnknownParameter*>(p)->value();
144
0
}
145
146
Data&
147
ParserCategory::param(const ExtensionParameter& param)
148
0
{
149
0
   checkParsed();
150
0
   Parameter* p = getParameterByData(param.getName());
151
0
   if (!p)
152
0
   {
153
0
      p = new UnknownParameter(param.getName());
154
0
      mUnknownParameters.push_back(p);
155
0
   } 
156
0
   return static_cast<UnknownParameter*>(p)->value();
157
0
}
158
159
// removing non-present parameter is allowed      
160
void
161
ParserCategory::remove(const ParamBase& paramType)
162
0
{
163
0
    checkParsed();
164
0
    removeParameterByEnum(paramType.getTypeNum());
165
0
}
166
167
void 
168
ParserCategory::remove(const ExtensionParameter& param)
169
0
{
170
0
   checkParsed();
171
0
   removeParameterByData(param.getName());
172
0
}
173
174
bool 
175
ParserCategory::exists(const ExtensionParameter& param) const
176
0
{
177
0
   checkParsed();
178
0
   return getParameterByData(param.getName()) != NULL;
179
0
}
180
181
void 
182
ParserCategory::removeParametersExcept(const ParameterTypeSet& set)
183
0
{
184
0
   checkParsed();
185
0
   for (ParameterList::iterator it = mParameters.begin();
186
0
        it != mParameters.end();)
187
0
   {
188
0
      if (set.find((*it)->getType()) == set.end())
189
0
      {
190
0
         freeParameter(*it);
191
0
         it = mParameters.erase(it);
192
0
      }
193
0
      else
194
0
      {
195
0
         ++it;
196
0
      }
197
0
   }
198
0
}
199
200
void 
201
ParserCategory::clearUnknownParameters()
202
631
{
203
631
   for (ParameterList::iterator it = mUnknownParameters.begin();
204
5.17k
        it != mUnknownParameters.end(); it++)
205
4.54k
   {
206
4.54k
      freeParameter(*it);
207
4.54k
   }   
208
631
   mUnknownParameters.clear();
209
631
}
210
211
void
212
ParserCategory::parseParameters(ParseBuffer& pb)
213
23.8k
{
214
1.94M
   while (!pb.eof() )
215
1.93M
   {
216
1.93M
      const char* start = pb.position();
217
1.93M
      pb.skipWhitespace();
218
219
1.93M
      if (  (!pb.eof() && *pb.position() == Symbols::SEMI_COLON[0]) )
220
1.92M
      {
221
         // extract the key
222
1.92M
         pb.skipChar();
223
1.92M
         const char* keyStart = pb.skipWhitespace();
224
1.92M
         static std::bitset<256> terminators1=Data::toBitset(" \t\r\n;=?>"); //!dlb! @ here?
225
1.92M
         const char* keyEnd = pb.skipToOneOf(terminators1);  
226
227
1.92M
         if((int)(keyEnd-keyStart) != 0)
228
1.92M
         {
229
1.92M
            ParameterTypes::Type type = ParameterTypes::getType(keyStart, (unsigned int)(keyEnd - keyStart));
230
1.92M
            static std::bitset<256> terminators2 = Data::toBitset(" \t\r\n;?>");
231
1.92M
            Parameter* p;
232
1.92M
            if (type == ParameterTypes::UNKNOWN || 
233
100k
               !(p=createParam(type, pb, terminators2,getPool())))
234
1.88M
            {
235
1.88M
               UnknownParameter* unknownParam = new (getPool()) UnknownParameter(keyStart,
236
1.88M
                                                                                 int((keyEnd - keyStart)),
237
1.88M
                                                                                 pb,
238
1.88M
                                                                                 terminators2);
239
240
1.88M
               if(!addParameter(unknownParam))
241
1.84M
               {
242
1.84M
                  freeParameter(unknownParam);
243
1.84M
               }
244
1.88M
            }
245
31.8k
            else
246
31.8k
            {
247
31.8k
               if(!addParameter(p))
248
29.7k
               {
249
29.7k
                  freeParameter(p);
250
29.7k
               }
251
31.8k
            }
252
1.92M
         }
253
1.92M
      }
254
8.30k
      else
255
8.30k
      {
256
8.30k
         pb.reset(start);
257
8.30k
         return;
258
8.30k
      }
259
1.93M
   }
260
23.8k
}      
261
262
bool
263
ParserCategory::addParameter(Parameter* param)
264
32.1k
{
265
32.1k
   resip_assert(param);
266
267
32.1k
   if (getParameterByEnum(param->getType()) == nullptr)
268
1.67k
   {
269
      // invoke the particular factory
270
1.67k
      mParameters.push_back(param);
271
1.67k
      return true;
272
1.67k
   }
273
30.4k
   else
274
30.4k
   {
275
      // RFC 3261 7.3.1 & 19.1.1
276
      // any given parameter-name MUST NOT appear more than once
277
30.4k
      WarningLog(<< "Duplicate parameter-name \"" << param->getName() << "\", skip it.");
278
30.4k
      return false;
279
30.4k
   }
280
32.1k
}
281
282
bool
283
ParserCategory::addParameter(UnknownParameter* unknownParam)
284
1.89M
{
285
1.89M
   resip_assert(unknownParam);
286
287
1.89M
   const Data& unknownParamName = unknownParam->getName();
288
289
1.89M
   if (getParameterByData(unknownParamName) == nullptr)
290
50.2k
   {
291
50.2k
      mUnknownParameters.push_back(unknownParam);
292
50.2k
      return true;
293
50.2k
   }
294
1.84M
   else
295
1.84M
   {
296
      // RFC 3261 7.3.1 & 19.1.1
297
      // any given parameter-name MUST NOT appear more than once
298
1.84M
      WarningLog(<< "Duplicate parameter-name \"" << unknownParamName << "\", skip it.");
299
1.84M
      return false;
300
1.84M
   }
301
1.89M
}
302
303
Parameter* 
304
ParserCategory::createParam(ParameterTypes::Type type, ParseBuffer& pb, const std::bitset<256>& terminators, PoolBase* pool)
305
12.3k
{
306
12.3k
   return 0;
307
12.3k
}
308
309
static Data up_Msgr("msgr");
310
311
EncodeStream&
312
ParserCategory::encodeParameters(EncodeStream& str) const
313
0
{
314
    
315
0
   for (ParameterList::const_iterator it = mParameters.begin();
316
0
        it != mParameters.end(); it++)
317
0
   {
318
#if 0
319
      // !cj! - may be wrong just hacking 
320
      // The goal of all this is not to add a tag if the tag is empty 
321
      ParameterTypes::Type type = (*it)->getType();
322
      
323
      if ( type ==  ParameterTypes::tag )
324
      {
325
         Parameter* p = (*it);
326
         DataParameter* d = dynamic_cast<DataParameter*>(p);
327
         
328
         Data& data = d->value();
329
         
330
         if ( !data.empty() )
331
         {
332
            str << Symbols::SEMI_COLON;
333
            // !ah! this is a TOTAL hack to work around an MSN bug that
334
            // !ah! requires a SPACE after the SEMI following the MIME type.
335
            if (it == mParameters.begin() && getParameterByData(up_Msgr))
336
            {
337
               str << Symbols::SPACE;
338
            }
339
340
            (*it)->encode(str);
341
         }
342
      }
343
      else
344
      {
345
         str << Symbols::SEMI_COLON;
346
         // !ah! this is a TOTAL hack to work around an MSN bug that
347
         // !ah! requires a SPACE after the SEMI following the MIME type.
348
         if (it == mParameters.begin() && getParameterByData(up_Msgr))
349
         {
350
            str << Symbols::SPACE;
351
         }
352
353
         (*it)->encode(str);
354
      }
355
      
356
#else
357
0
      str << Symbols::SEMI_COLON;
358
      // !ah! this is a TOTAL hack to work around an MSN bug that
359
      // !ah! requires a SPACE after the SEMI following the MIME type.
360
0
      if (it == mParameters.begin() && getParameterByData(up_Msgr))
361
0
      {
362
0
         str << Symbols::SPACE;
363
0
      }
364
      
365
0
      (*it)->encode(str);
366
0
#endif
367
0
   }
368
0
   for (ParameterList::const_iterator it = mUnknownParameters.begin();
369
0
        it != mUnknownParameters.end(); it++)
370
0
   {
371
0
      str << Symbols::SEMI_COLON;
372
0
      (*it)->encode(str);
373
0
   }
374
0
   return str;
375
0
}
376
377
EncodeStream&
378
resip::operator<<(EncodeStream& stream, const ParserCategory& category)
379
0
{
380
0
   category.checkParsed();
381
0
   return category.encode(stream);
382
0
}
383
384
Parameter* 
385
ParserCategory::getParameterByEnum(ParameterTypes::Type type) const
386
50.2k
{
387
50.2k
   for (ParameterList::const_iterator it = mParameters.begin();
388
51.1k
        it != mParameters.end(); it++)
389
37.3k
   {
390
37.3k
      if ((*it)->getType() == type)
391
36.5k
      {
392
36.5k
         return *it;
393
36.5k
      }
394
37.3k
   }
395
13.7k
   return 0;
396
50.2k
}
397
398
void
399
ParserCategory::setParameter(const Parameter* parameter)
400
0
{
401
0
   resip_assert(parameter);
402
403
0
   for (ParameterList::iterator it = mParameters.begin();
404
0
        it != mParameters.end(); it++)
405
0
   {
406
0
      if ((*it)->getType() == parameter->getType())
407
0
      {
408
0
         freeParameter(*it);
409
0
         mParameters.erase(it);
410
0
         mParameters.push_back(parameter->clone());
411
0
         return;
412
0
      }
413
0
   }
414
415
   // !dlb! kinda hacky -- what is the correct semantics here?
416
   // should be quietly add, quietly do nothing, throw?
417
0
   mParameters.push_back(parameter->clone());
418
0
}
419
420
void 
421
ParserCategory::removeParameterByEnum(ParameterTypes::Type type)
422
0
{
423
   // remove all instances
424
0
   for (ParameterList::iterator it = mParameters.begin();
425
0
        it != mParameters.end();)
426
0
   {
427
0
      if ((*it)->getType() == type)
428
0
      {
429
0
         freeParameter(*it);
430
0
         it = mParameters.erase(it);
431
0
      }
432
0
      else
433
0
      {
434
0
         ++it;
435
0
      }
436
0
   }
437
0
 }
438
439
Parameter* 
440
ParserCategory::getParameterByData(const Data& data) const
441
1.89M
{
442
1.89M
   for (ParameterList::const_iterator it = mUnknownParameters.begin();
443
5.87M
        it != mUnknownParameters.end(); it++)
444
5.82M
   {
445
5.82M
      if (isEqualNoCase((*it)->getName(), data))
446
1.84M
      {
447
1.84M
         return *it;
448
1.84M
      }
449
5.82M
   }
450
50.2k
   return 0;
451
1.89M
}
452
453
void 
454
ParserCategory::removeParameterByData(const Data& data)
455
0
{
456
   // remove all instances
457
0
   for (ParameterList::iterator it = mUnknownParameters.begin();
458
0
        it != mUnknownParameters.end();)
459
0
   {
460
0
      if ((*it)->getName() == data)
461
0
      {
462
0
         freeParameter(*it);
463
0
         it = mUnknownParameters.erase(it);
464
0
      }
465
0
      else
466
0
      {
467
0
         ++it;
468
0
      }
469
0
   }
470
0
}
471
472
Data
473
ParserCategory::commutativeParameterHash() const
474
0
{
475
0
   Data buffer;
476
0
   Data working;
477
478
0
   for (ParameterList::const_iterator i = mParameters.begin(); i != mParameters.end(); ++i)
479
0
   {
480
0
      if ((*i)->getType() != ParameterTypes::lr)
481
0
      {
482
0
         buffer.clear();
483
0
         {
484
0
            DataStream strm(buffer);
485
0
            (*i)->encode(strm);
486
0
         }
487
0
         working ^= buffer;
488
0
      }
489
0
   }
490
491
0
   buffer.clear();
492
0
   for (ParameterList::const_iterator i = mUnknownParameters.begin(); i != mUnknownParameters.end(); ++i)
493
0
   {
494
0
      UnknownParameter* p = static_cast<UnknownParameter*>(*i);
495
0
      buffer = p->getName();
496
0
      buffer += p->value();
497
0
      working ^= buffer;
498
0
   }
499
   
500
0
   return working;
501
0
}
502
503
const Data&
504
ParserCategory::errorContext() const
505
72.5k
{
506
72.5k
   return Headers::getHeaderName(mHeaderType);
507
72.5k
}
508
509
/* ====================================================================
510
 * The Vovida Software License, Version 1.0 
511
 * 
512
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
513
 * 
514
 * Redistribution and use in source and binary forms, with or without
515
 * modification, are permitted provided that the following conditions
516
 * are met:
517
 * 
518
 * 1. Redistributions of source code must retain the above copyright
519
 *    notice, this list of conditions and the following disclaimer.
520
 * 
521
 * 2. Redistributions in binary form must reproduce the above copyright
522
 *    notice, this list of conditions and the following disclaimer in
523
 *    the documentation and/or other materials provided with the
524
 *    distribution.
525
 * 
526
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
527
 *    and "Vovida Open Communication Application Library (VOCAL)" must
528
 *    not be used to endorse or promote products derived from this
529
 *    software without prior written permission. For written
530
 *    permission, please contact vocal@vovida.org.
531
 *
532
 * 4. Products derived from this software may not be called "VOCAL", nor
533
 *    may "VOCAL" appear in their name, without prior written
534
 *    permission of Vovida Networks, Inc.
535
 * 
536
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
537
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
538
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
539
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
540
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
541
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
542
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
543
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
544
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
545
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
546
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
547
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
548
 * DAMAGE.
549
 * 
550
 * ====================================================================
551
 * 
552
 * This software consists of voluntary contributions made by Vovida
553
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
554
 * Inc.  For more information on Vovida Networks, Inc., please see
555
 * <http://www.vovida.org/>.
556
 *
557
 */
558
559
/* Local Variables: */
560
/* c-file-style: "ellemtel" */
561
/* End: */