reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
ParserCategory.cxx
Go to the documentation of this file.
1#if defined(HAVE_CONFIG_H)
2#include "config.h"
3#endif
4
10#include "rutil/ParseBuffer.hxx"
11#include "rutil/compat.hxx"
12
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
24using namespace resip;
25using namespace std;
26
29
31 Headers::Type headerType,
32 PoolBase* pool)
33 : LazyParser(headerFieldValue),
34 mParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
35 mUnknownParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
36 mPool(pool),
37 mHeaderType(headerType)
38{
39}
40
42 int length,
43 Headers::Type type,
44 PoolBase* pool):
45 LazyParser(buf, length),
46 mParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
47 mUnknownParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
48 mPool(pool),
49 mHeaderType(type)
50{}
51
53 : LazyParser(),
54 mParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
55 mUnknownParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
56 mPool(pool),
57 mHeaderType(Headers::NONE)
58{
59}
60
62 PoolBase* pool)
63 : LazyParser(rhs),
64 mParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
65 mUnknownParameters(StlPoolAllocator<Parameter*, PoolBase>(pool)),
66 mPool(pool),
67 mHeaderType(rhs.mHeaderType)
68{
69 if (isParsed())
70 {
71 copyParametersFrom(rhs);
72 }
73}
74
77{
78 if (this != &rhs)
79 {
80 clear();
83 if (rhs.isParsed())
84 {
85 copyParametersFrom(rhs);
86 }
87 }
88 return *this;
89}
90
91void
92ParserCategory::clear()
93{
94 //DebugLog(<<"ParserCategory::clear");
96
97 while(!mParameters.empty())
98 {
100 mParameters.pop_back();
101 }
102
103 while(!mUnknownParameters.empty())
104 {
106 mUnknownParameters.pop_back();
107 }
108}
109
110void
111ParserCategory::copyParametersFrom(const ParserCategory& other)
112{
113 mParameters.reserve(other.mParameters.size());
114 mUnknownParameters.reserve(other.mUnknownParameters.size());
115
116 for (ParameterList::const_iterator it = other.mParameters.begin();
117 it != other.mParameters.end(); it++)
118 {
119 mParameters.push_back((*it)->clone());
120 }
121 for (ParameterList::const_iterator it = other.mUnknownParameters.begin();
122 it != other.mUnknownParameters.end(); it++)
123 {
124 mUnknownParameters.push_back((*it)->clone());
125 }
126}
127
129{
130 clear();
131}
132
133const Data&
135{
136 checkParsed();
137 Parameter* p = getParameterByData(param.getName());
138 if (!p)
139 {
140 InfoLog(<< "Referenced an unknown parameter " << param.getName());
141 throw Exception("Missing unknown parameter", __FILE__, __LINE__);
142 }
143 return static_cast<UnknownParameter*>(p)->value();
144}
145
146Data&
148{
149 checkParsed();
150 Parameter* p = getParameterByData(param.getName());
151 if (!p)
152 {
153 p = new UnknownParameter(param.getName());
154 mUnknownParameters.push_back(p);
155 }
156 return static_cast<UnknownParameter*>(p)->value();
157}
158
159// removing non-present parameter is allowed
160void
162{
163 checkParsed();
166
167void
174bool
176{
177 checkParsed();
178 return getParameterByData(param.getName()) != NULL;
179}
181void
183{
184 checkParsed();
185 for (ParameterList::iterator it = mParameters.begin();
186 it != mParameters.end();)
188 if (set.find((*it)->getType()) == set.end())
189 {
190 freeParameter(*it);
191 it = mParameters.erase(it);
192 }
193 else
194 {
195 ++it;
196 }
197 }
198}
199
200void
202{
203 for (ParameterList::iterator it = mUnknownParameters.begin();
204 it != mUnknownParameters.end(); it++)
205 {
206 freeParameter(*it);
207 }
208 mUnknownParameters.clear();
209}
210
211void
213{
214 while (!pb.eof() )
215 {
216 const char* start = pb.position();
217 pb.skipWhitespace();
218
219 if ( (!pb.eof() && *pb.position() == Symbols::SEMI_COLON[0]) )
220 {
221 // extract the key
222 pb.skipChar();
223 const char* keyStart = pb.skipWhitespace();
224 static std::bitset<256> terminators1=Data::toBitset(" \t\r\n;=?>");
225 const char* keyEnd = pb.skipToOneOf(terminators1);
226
227 if((int)(keyEnd-keyStart) != 0)
228 {
229 ParameterTypes::Type type = ParameterTypes::getType(keyStart, (unsigned int)(keyEnd - keyStart));
230 static std::bitset<256> terminators2 = Data::toBitset(" \t\r\n;?>");
231 Parameter* p;
232 if (type == ParameterTypes::UNKNOWN ||
233 !(p=createParam(type, pb, terminators2,getPool())))
234 {
235 UnknownParameter* unknownParam = new (getPool()) UnknownParameter(keyStart,
236 int((keyEnd - keyStart)),
237 pb,
238 terminators2);
239
240 if(!addParameter(unknownParam))
241 {
242 freeParameter(unknownParam);
243 }
244 }
245 else
246 {
247 if(!addParameter(p))
248 {
249 freeParameter(p);
250 }
251 }
252 }
253 }
254 else
255 {
256 pb.reset(start);
257 return;
258 }
259 }
260}
261
262bool
264{
266
267 if (getParameterByEnum(param->getType()) == nullptr)
268 {
269 // invoke the particular factory
270 mParameters.push_back(param);
271 return true;
272 }
273 else
274 {
275 // RFC 3261 7.3.1 & 19.1.1
276 // any given parameter-name MUST NOT appear more than once
277 InfoLog(<< "Duplicate parameter-name \"" << param->getName() << "\", skip it.");
278 return false;
279 }
280}
281
282bool
284{
285 resip_assert(unknownParam);
286
287 const Data& unknownParamName = unknownParam->getName();
288
289 if (getParameterByData(unknownParamName) == nullptr)
290 {
291 mUnknownParameters.push_back(unknownParam);
292 return true;
293 }
294 else
295 {
296 // RFC 3261 7.3.1 & 19.1.1
297 // any given parameter-name MUST NOT appear more than once
298 InfoLog(<< "Duplicate parameter-name \"" << unknownParamName << "\", skip it.");
299 return false;
300 }
301}
302
303Parameter*
304ParserCategory::createParam(ParameterTypes::Type type, ParseBuffer& pb, const std::bitset<256>& terminators, PoolBase* pool)
305{
306 return 0;
307}
308
309static Data up_Msgr("msgr");
310
312ParserCategory::encodeParameters(EncodeStream& str) const
313{
314
315 for (ParameterList::const_iterator it = mParameters.begin();
316 it != mParameters.end(); it++)
317 {
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 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 if (it == mParameters.begin() && getParameterByData(up_Msgr))
361 {
362 str << Symbols::SPACE;
363 }
364
365 (*it)->encode(str);
366#endif
367 }
368 for (ParameterList::const_iterator it = mUnknownParameters.begin();
369 it != mUnknownParameters.end(); it++)
370 {
371 str << Symbols::SEMI_COLON;
372 (*it)->encode(str);
373 }
374 return str;
375}
376
378resip::operator<<(EncodeStream& stream, const ParserCategory& category)
379{
380 category.checkParsed();
381 return category.encode(stream);
382}
383
384Parameter*
386{
387 for (ParameterList::const_iterator it = mParameters.begin();
388 it != mParameters.end(); it++)
389 {
390 if ((*it)->getType() == type)
391 {
392 return *it;
393 }
394 }
395 return 0;
396}
397
398void
400{
401 resip_assert(parameter);
402
403 for (ParameterList::iterator it = mParameters.begin();
404 it != mParameters.end(); it++)
405 {
406 if ((*it)->getType() == parameter->getType())
407 {
408 freeParameter(*it);
409 mParameters.erase(it);
410 mParameters.push_back(parameter->clone());
411 return;
412 }
413 }
414
415 // !dlb! kinda hacky -- what is the correct semantics here?
416 // should be quietly add, quietly do nothing, throw?
417 mParameters.push_back(parameter->clone());
418}
419
420void
422{
423 // remove all instances
424 for (ParameterList::iterator it = mParameters.begin();
425 it != mParameters.end();)
426 {
427 if ((*it)->getType() == type)
428 {
429 freeParameter(*it);
430 it = mParameters.erase(it);
431 }
432 else
433 {
434 ++it;
435 }
436 }
437 }
438
439Parameter*
441{
442 for (ParameterList::const_iterator it = mUnknownParameters.begin();
443 it != mUnknownParameters.end(); it++)
444 {
445 if (isEqualNoCase((*it)->getName(), data))
446 {
447 return *it;
448 }
449 }
450 return 0;
451}
452
453void
455{
456 // remove all instances
457 for (ParameterList::iterator it = mUnknownParameters.begin();
458 it != mUnknownParameters.end();)
459 {
460 if ((*it)->getName() == data)
461 {
462 freeParameter(*it);
463 it = mUnknownParameters.erase(it);
464 }
465 else
466 {
467 ++it;
468 }
469 }
470}
471
472Data
474{
475 Data buffer;
476 Data working;
477
478 for (ParameterList::const_iterator i = mParameters.begin(); i != mParameters.end(); ++i)
479 {
480 if ((*i)->getType() != ParameterTypes::lr)
481 {
482 buffer.clear();
483 {
484 DataStream strm(buffer);
485 (*i)->encode(strm);
486 }
487 working ^= buffer;
488 }
489 }
490
491 buffer.clear();
492 for (ParameterList::const_iterator i = mUnknownParameters.begin(); i != mUnknownParameters.end(); ++i)
493 {
494 UnknownParameter* p = static_cast<UnknownParameter*>(*i);
495 buffer = p->getName();
496 buffer += p->value();
497 working ^= buffer;
498 }
499
500 return working;
501}
502
503const Data&
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: */
#define InfoLog(args_)
Definition Logger.hxx:131
static Data up_Msgr("msgr")
#define resip_assert(x)
This file needs to work for both C and C++ code.
Generically represents miscellaneous parameter data.
An iostream that operates on an existing Data.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
Data & clear()
Clears the contents of this Data.
Definition Data.hxx:800
static std::bitset< 256 > toBitset(const resip::Data &chars)
Creates a bitset reflecting the contents of this data (as a set) ie.
Definition Data.cxx:2477
Maps from header name to derived ParserCategory.
static const Data & getHeaderName(int)
Definition Headers.cxx:37
The base-class for all lazily-parsed SIP grammar elements.
EncodeStream & encode(EncodeStream &str) const
Encodes this element to a stream, in the fashion it should be represented on the wire.
void checkParsed() const
LazyParser & operator=(const LazyParser &rhs)
bool isParsed() const
Returns true iff a parse has been attempted.
virtual ParameterTypes::Type getTypeNum() const =0
static Type getType(const char *start, size_t length)
does a convert to enum from a pointer into the HFV raw buffer
virtual Parameter * clone() const =0
ParameterTypes::Type getType() const
Definition Parameter.cxx:16
Provides string-parsing functionality with protection from buffer overflow.
CurrentPosition skipWhitespace()
CurrentPosition position() const
void reset(const char *pos)
CurrentPosition skipToOneOf(const char *cs)
CurrentPosition skipChar()
Exception class used by ParserCategory.
Base class for all SIP grammar elements that can have parameters.
void removeParameterByData(const Data &data)
void remove(const ParamBase &paramType)
Removes a natively supported parameter, if the parameter is present.
void setParameter(const Parameter *parameter)
Parameter * getParameterByData(const Data &data) const
Parameter * getParameterByEnum(ParameterTypes::Type type) const
Data commutativeParameterHash() const
ParserCategory(const HeaderFieldValue &headerFieldValue, Headers::Type type, PoolBase *pool=0)
ParameterList mUnknownParameters
ParserCategory & operator=(const ParserCategory &rhs)
void removeParameterByEnum(ParameterTypes::Type type)
void parseParameters(ParseBuffer &pb)
bool addParameter(Parameter *param)
virtual Parameter * createParam(ParameterTypes::Type type, ParseBuffer &pb, const std::bitset< 256 > &terminators, PoolBase *pool)
static const ParameterTypeSet EmptyParameterTypeSet
EncodeStream & encodeParameters(EncodeStream &str) const
Encodes parameters as they should appear on the wire.
virtual const Data & errorContext() const
bool exists(const ParamBase &paramType) const
Checks for the existence of a natively supported parameter.
std::set< ParameterTypes::Type > ParameterTypeSet
void removeParametersExcept(const ParameterTypeSet &set=EmptyParameterTypeSet)
Removes all known parameters except those that are specified in set.
void freeParameter(Parameter *p)
const Data & param(const ExtensionParameter &param) const
Const accessor for non-natively-supported parameter types.
A dirt-simple lightweight stl pool allocator meant for use in short-lifetime objects.
static const char * SEMI_COLON
Definition Symbols.hxx:30
static const char * SPACE
Definition Symbols.hxx:34
Generically used to represent any parameter that is not known by the implmentation.
virtual const Data & getName() const
This file is used to handle compatibility fixes/tweaks so reSIProcate can function on multiple platfo...
dcm! – add UnusedChecking(_enum) below;
bool isEqualNoCase(const Data &left, const Data &right)
Definition Data.hxx:1116
EncodeStream & operator<<(EncodeStream &strm, const BaseException &e)
#define EncodeStream