Coverage Report

Created: 2026-09-14 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/resiprocate/resip/stack/Uri.cxx
Line
Count
Source
1
#if defined(HAVE_CONFIG_H)
2
#include "config.h"
3
#endif
4
5
#include <ctype.h>
6
#include <set>
7
8
#include "resip/stack/Embedded.hxx"
9
#include "resip/stack/Helper.hxx"
10
#include "resip/stack/NameAddr.hxx"
11
#include "resip/stack/SipMessage.hxx"
12
#include "resip/stack/Symbols.hxx"
13
#include "resip/stack/UnknownParameter.hxx"
14
#include "resip/stack/Uri.hxx"
15
#include "rutil/DataStream.hxx"
16
#include "rutil/DnsUtil.hxx"
17
#include "rutil/Logger.hxx"
18
#include "rutil/ParseBuffer.hxx"
19
//#include "rutil/WinLeakCheck.hxx"  // not compatible with placement new used below
20
21
using namespace resip;
22
23
#define RESIPROCATE_SUBSYSTEM Subsystem::SIP
24
#define HANDLE_CHARACTER_ESCAPING //undef for old behaviour
25
26
static bool initAllTables()
27
2
{
28
2
   Uri::getUserEncodingTable();
29
2
   Uri::getPasswordEncodingTable();
30
2
   Uri::getLocalNumberTable();
31
2
   Uri::getGlobalNumberTable();
32
2
   Uri::getUrnEncodingTable();
33
2
   return true;
34
2
}
35
36
const bool Uri::tablesMightBeInitialized(initAllTables());
37
38
Uri::Uri(PoolBase* pool) 
39
27.2k
   : ParserCategory(pool),
40
27.2k
     mScheme(Data::Share, Symbols::DefaultSipScheme),
41
27.2k
     mPort(0),
42
27.2k
     mHostCanonicalized(false),
43
27.2k
     mIsBetweenAngleQuotes(false),
44
27.2k
     mIsBareAddrSpec(false)
45
27.2k
{
46
27.2k
}
47
48
Uri::Uri(const HeaderFieldValue& hfv, Headers::Type type, PoolBase* pool) :
49
6.64k
   ParserCategory(hfv, type, pool),
50
6.64k
   mPort(0),
51
6.64k
   mHostCanonicalized(false),
52
6.64k
   mIsBetweenAngleQuotes(false),
53
6.64k
   mIsBareAddrSpec(false)
54
6.64k
{}
55
56
57
static const Data parseContext("Uri constructor");
58
Uri::Uri(const Data& data)
59
0
   : ParserCategory(),
60
0
     mScheme(Symbols::DefaultSipScheme),
61
0
     mPort(0),
62
0
     mHostCanonicalized(false),
63
0
     mIsBetweenAngleQuotes(false),
64
0
     mIsBareAddrSpec(false)
65
0
{
66
0
   HeaderFieldValue hfv(data.data(), data.size());
67
   // must copy because parse creates overlays
68
0
   Uri tmp(hfv, Headers::UNKNOWN);
69
0
   tmp.checkParsed();
70
0
   *this = tmp;
71
0
}
72
73
Uri::Uri(const Uri& rhs,
74
         PoolBase* pool)
75
0
   : ParserCategory(rhs, pool),
76
0
     mScheme(rhs.mScheme),
77
0
     mHost(rhs.mHost),
78
0
     mUser(rhs.mUser),
79
0
     mUserParameters(rhs.mUserParameters),
80
0
     mPort(rhs.mPort),
81
0
     mPassword(rhs.mPassword),
82
0
     mNetNs(rhs.mNetNs),
83
0
     mPath(rhs.mPath),
84
0
     mHostCanonicalized(rhs.mHostCanonicalized),
85
0
     mCanonicalHost(rhs.mCanonicalHost),
86
0
     mIsBetweenAngleQuotes(rhs.mIsBetweenAngleQuotes),
87
0
     mIsBareAddrSpec(rhs.mIsBareAddrSpec),
88
0
     mEmbeddedHeadersText(rhs.mEmbeddedHeadersText.get() ? new Data(*rhs.mEmbeddedHeadersText) : 0),
89
0
     mEmbeddedHeaders(rhs.mEmbeddedHeaders.get() ? new SipMessage(*rhs.mEmbeddedHeaders) : 0),
90
0
     mUserRaw(rhs.mUserRaw ? new Data(*rhs.mUserRaw) : nullptr)
91
0
{}
92
93
94
Uri::~Uri()
95
33.8k
{}
96
97
// RFC 3261 19.1.6
98
#if 0  // deprecated
99
Uri
100
Uri::fromTel(const Uri& tel, const Data& host)
101
{
102
   resip_assert(tel.scheme() == Symbols::Tel);
103
104
   Uri u;
105
   u.scheme() = Symbols::Sip;
106
   u.user() = tel.user();
107
   u.host() = host;
108
   u.param(p_user) = Symbols::Phone;
109
110
   // need to sort the user parameters
111
   if (!tel.userParameters().empty())
112
   {
113
      DebugLog(<< "Uri::fromTel: " << tel.userParameters());
114
      Data isub;
115
      Data postd;
116
117
      int totalSize  = 0;
118
      std::set<Data> userParameters;
119
120
      ParseBuffer pb(tel.userParameters().data(), tel.userParameters().size());
121
      while (true)
122
      {
123
         const char* anchor = pb.position();
124
         pb.skipToChar(Symbols::SEMI_COLON[0]);
125
         Data param = pb.data(anchor);
126
         // !dlb! not supposed to lowercase extension parameters
127
         param.lowercase();
128
         totalSize += param.size() + 1;
129
130
         if (param.prefix(Symbols::Isub))
131
         {
132
            isub = param;
133
         }
134
         else if (param.prefix(Symbols::Postd))
135
         {
136
            postd = param;
137
         }
138
         else
139
         {
140
            userParameters.insert(param);
141
         }
142
         if (pb.eof())
143
         {
144
            break;
145
         }
146
         else
147
         {
148
            pb.skipChar();
149
         }
150
      }
151
152
      u.userParameters().reserve(totalSize);
153
      if (!isub.empty())
154
      {
155
         u.userParameters() = isub;
156
      }
157
      if (!postd.empty())
158
      {
159
         if (!u.userParameters().empty())
160
         {
161
            u.userParameters() += Symbols::SEMI_COLON[0];
162
         }
163
         u.userParameters() += postd;
164
      }
165
      
166
      for(std::set<Data>::const_iterator i = userParameters.begin();
167
          i != userParameters.end(); ++i)
168
      {
169
         DebugLog(<< "Adding param: " << *i);
170
         if (!u.userParameters().empty())
171
         {
172
            u.userParameters() += Symbols::SEMI_COLON[0];
173
         }
174
         u.userParameters() += *i;
175
      }
176
   }
177
178
   return u;
179
}
180
#endif // deprecated
181
182
Uri
183
Uri::fromTel(const Uri& tel, const Uri& hostUri)
184
0
{
185
0
   resip_assert(tel.scheme() == Symbols::Tel);
186
187
0
   Uri u(hostUri);
188
0
   u.scheme() = Symbols::Sip;
189
0
   u.user() = tel.user();
190
0
   u.param(p_user) = Symbols::Phone;
191
192
   // need to sort the user parameters
193
0
   if (!tel.userParameters().empty())
194
0
   {
195
0
      DebugLog(<< "Uri::fromTel: " << tel.userParameters());
196
0
      Data isub;
197
0
      Data postd;
198
199
0
      int totalSize  = 0;
200
0
      std::set<Data> userParameters;
201
202
0
      ParseBuffer pb(tel.userParameters().data(), tel.userParameters().size());
203
0
      while (true)
204
0
      {
205
0
         const char* anchor = pb.position();
206
0
         pb.skipToChar(Symbols::SEMI_COLON[0]);
207
0
         Data param = pb.data(anchor);
208
         // !dlb! not supposed to lowercase extension parameters
209
0
         param.lowercase();
210
0
         totalSize += (int)param.size() + 1;
211
212
0
         if (param.prefix(Symbols::Isub))
213
0
         {
214
0
            isub = param;
215
0
         }
216
0
         else if (param.prefix(Symbols::Postd))
217
0
         {
218
0
            postd = param;
219
0
         }
220
0
         else
221
0
         {
222
0
            userParameters.insert(param);
223
0
         }
224
0
         if (pb.eof())
225
0
         {
226
0
            break;
227
0
         }
228
0
         else
229
0
         {
230
0
            pb.skipChar();
231
0
         }
232
0
      }
233
234
0
      u.userParameters().reserve(totalSize);
235
0
      if (!isub.empty())
236
0
      {
237
0
         u.userParameters() = isub;
238
0
      }
239
0
      if (!postd.empty())
240
0
      {
241
0
         if (!u.userParameters().empty())
242
0
         {
243
0
            u.userParameters() += Symbols::SEMI_COLON[0];
244
0
         }
245
0
         u.userParameters() += postd;
246
0
      }
247
      
248
0
      for(std::set<Data>::const_iterator i = userParameters.begin();
249
0
          i != userParameters.end(); ++i)
250
0
      {
251
0
         DebugLog(<< "Adding param: " << *i);
252
0
         if (!u.userParameters().empty())
253
0
         {
254
0
            u.userParameters() += Symbols::SEMI_COLON[0];
255
0
         }
256
0
         u.userParameters() += *i;
257
0
      }
258
0
   }
259
260
0
   return u;
261
0
}
262
263
bool
264
Uri::isEnumSearchable() const
265
0
{
266
0
   checkParsed();
267
0
   int digits = 0;
268
269
0
   if(mScheme != Symbols::Tel)
270
0
   {
271
0
      StackLog(<< "not a tel Uri");
272
0
      return false;
273
0
   }
274
275
0
   if(mUser.size() < 4)
276
0
   {
277
0
      StackLog(<< "user part of Uri empty or too short for E.164");
278
0
      return false;
279
0
   }
280
281
   // E.164 numbers must begin with a + and have at least
282
   // 3 digits
283
0
   if(mUser[0] != '+')
284
0
   {
285
0
      StackLog(<< "user part of Uri does not begin with `+' or too short");
286
0
      return false;
287
0
   }
288
289
   // count the digits (skip the leading `+')
290
0
   for(const char* i=user().begin() + 1; i!= user().end(); i++)
291
0
   {
292
0
      if (isdigit(static_cast< unsigned char >(*i)))
293
0
      {
294
0
         digits++;
295
0
      }
296
0
      else
297
0
      {
298
0
         if (*i != '-')
299
0
         {
300
0
            StackLog(<< "user part of Uri contains non-digit: " << *i);
301
0
            return false; // Only digits and '-' permitted
302
0
         }
303
0
      }
304
0
   }
305
0
   if(digits > 15)
306
0
   {
307
      // E.164 only permits 15 digits in a phone number
308
0
      StackLog(<< "user part of Uri contains more than 15 digits");
309
0
      return false;
310
0
   }
311
312
0
   DebugLog(<< "is in E.164 format for ENUM: " << mUser);
313
0
   return true;
314
0
}
315
316
std::vector<Data> 
317
Uri::getEnumLookups(const std::vector<Data>& suffixes) const
318
0
{
319
0
   std::vector<Data> results;
320
0
   Data prefix;
321
0
   if (isEnumSearchable())
322
0
   {
323
      // skip the leading +
324
0
      for (const char* i=user().end()-1 ; i!= user().begin(); --i)
325
0
      {
326
0
         if (isdigit(static_cast< unsigned char >(*i)))
327
0
         {
328
0
            prefix += *i;
329
0
            prefix += Symbols::DOT;
330
0
         }
331
0
      }
332
0
      StackLog(<< "E.164 number reversed for ENUM query: " << prefix);
333
0
      for (std::vector<Data>::const_iterator j=suffixes.begin(); j != suffixes.end(); ++j)
334
0
      {
335
0
         results.push_back(prefix + *j);
336
0
      }
337
0
   }
338
0
   return results;
339
0
}
340
341
bool
342
Uri::hasEmbedded() const
343
0
{
344
0
   checkParsed(); 
345
0
   return (mEmbeddedHeadersText.get() && !mEmbeddedHeadersText->empty()) || mEmbeddedHeaders.get() != 0;
346
0
}
347
348
void 
349
Uri::removeEmbedded()
350
0
{
351
0
   checkParsed();
352
0
   mEmbeddedHeaders.reset();
353
0
   mEmbeddedHeadersText.reset();
354
0
}
355
356
Uri&
357
Uri::operator=(const Uri& rhs)
358
2.94k
{
359
2.94k
   if (this != &rhs)
360
2.94k
   {
361
2.94k
      ParserCategory::operator=(rhs);
362
2.94k
      mScheme = rhs.mScheme;
363
2.94k
      mHost = rhs.mHost;
364
2.94k
      mPath = rhs.mPath;
365
2.94k
      mHostCanonicalized = rhs.mHostCanonicalized;
366
2.94k
      mCanonicalHost = rhs.mCanonicalHost;
367
2.94k
      mUser = rhs.mUser;
368
2.94k
      if (rhs.mUserRaw)
369
66
      {
370
66
         mUserRaw.reset(new Data(*rhs.mUserRaw));
371
66
      }
372
2.87k
      else
373
2.87k
      {
374
2.87k
         mUserRaw.reset();
375
2.87k
      }
376
2.94k
      mUserParameters = rhs.mUserParameters;
377
2.94k
      mPort = rhs.mPort;
378
2.94k
      mPassword = rhs.mPassword;
379
2.94k
      mNetNs = rhs.mNetNs;
380
2.94k
      if (rhs.mEmbeddedHeaders.get() != 0)
381
0
      {
382
0
         mEmbeddedHeaders.reset(new SipMessage(*rhs.mEmbeddedHeaders));
383
0
      }
384
2.94k
      else if(rhs.mEmbeddedHeadersText.get() != 0)
385
1.07k
      {
386
1.07k
         if(!mEmbeddedHeadersText.get())
387
1.07k
         {
388
1.07k
            mEmbeddedHeadersText.reset(new Data(*rhs.mEmbeddedHeadersText));
389
1.07k
         }
390
0
         else
391
0
         {
392
            // !bwc! Data::operator= is smart enough to handle this safely.
393
0
            *mEmbeddedHeadersText = *rhs.mEmbeddedHeadersText;
394
0
         }
395
1.07k
      }
396
2.94k
   }
397
2.94k
   return *this;
398
2.94k
}
399
400
/**
401
  @class OrderUnknownParameters
402
  @brief used as a comparator for sorting purposes
403
  */
404
class OrderUnknownParameters
405
{
406
   public:
407
      /**
408
        @brief constructor ; never called explicitly
409
        */
410
0
      OrderUnknownParameters() { notUsed=false; };
411
412
      /**
413
        @brief empty destructor
414
        */
415
0
      ~OrderUnknownParameters() {};
416
417
      /**
418
        @brief used as a comparator for sorting purposes
419
         This does a straight Data comparison for name and returns true/false
420
        @param p1 pointer to parameter 1
421
        @param p2 pointer to parameter 2
422
        @return true if p1->getName() is less than p2->getName() 
423
         else return false
424
        */
425
      bool operator()(const Parameter* p1, const Parameter* p2) const
426
0
      {
427
0
         return dynamic_cast<const UnknownParameter*>(p1)->getName() < dynamic_cast<const UnknownParameter*>(p2)->getName();
428
0
      }
429
430
   private:
431
      bool notUsed;
432
};
433
434
bool Uri::compareUriParametersEqual(Parameter* param1, Parameter* param2)
435
0
{
436
0
   if (!param1 || !param2)
437
0
   {
438
0
      return false;
439
0
   }
440
441
0
   switch (param1->getType()) {
442
0
      case ParameterTypes::user:
443
0
      case ParameterTypes::method:
444
0
      case ParameterTypes::maddr:
445
0
      case ParameterTypes::transport:
446
0
      case ParameterTypes::rinstance:
447
0
      case ParameterTypes::comp:
448
0
      case ParameterTypes::extension:
449
0
      case ParameterTypes::wsSrcIp:
450
0
      case ParameterTypes::sigcompId:
451
0
         return isEqualNoCase(dynamic_cast<DataParameter*>(param1)->value(),
452
0
                              dynamic_cast<DataParameter*>(param2)->value());
453
454
0
      case ParameterTypes::ttl:
455
0
      case ParameterTypes::duration:
456
0
      case ParameterTypes::wsSrcPort:
457
0
         return dynamic_cast<UInt32Parameter*>(param1)->value() ==
458
0
                dynamic_cast<UInt32Parameter*>(param2)->value();
459
460
0
      case ParameterTypes::gr:
461
0
         return isEqualNoCase(dynamic_cast<ExistsOrDataParameter*>(param1)->value(),
462
0
                              dynamic_cast<ExistsOrDataParameter*>(param2)->value());
463
464
0
      case ParameterTypes::lr:
465
0
      case ParameterTypes::ob:
466
         // Exists parameters are equal.
467
0
         return true;
468
469
0
      default:
470
         // Other parameters are not considered.
471
         // Parameters may be added accordingly to RFCs.
472
0
         return true;
473
0
   }
474
0
}
475
476
bool Uri::compareUriParametersLessThan(Parameter* param1, Parameter* param2)
477
0
{
478
0
   if (!param1 || !param2)
479
0
   {
480
0
      return false;
481
0
   }
482
483
0
   switch (param1->getType()) {
484
0
      case ParameterTypes::user:
485
0
      case ParameterTypes::method:
486
0
      case ParameterTypes::maddr:
487
0
      case ParameterTypes::transport:
488
0
      case ParameterTypes::rinstance:
489
0
      case ParameterTypes::comp:
490
0
      case ParameterTypes::extension:
491
0
      case ParameterTypes::wsSrcIp:
492
0
      case ParameterTypes::sigcompId:
493
0
         return isLessThanNoCase(dynamic_cast<DataParameter*>(param1)->value(),
494
0
                                 dynamic_cast<DataParameter*>(param2)->value());
495
496
0
      case ParameterTypes::ttl:
497
0
      case ParameterTypes::duration:
498
0
      case ParameterTypes::wsSrcPort:
499
0
         return dynamic_cast<UInt32Parameter*>(param1)->value() <
500
0
                dynamic_cast<UInt32Parameter*>(param2)->value();
501
502
0
      case ParameterTypes::gr:
503
0
         return isLessThanNoCase(dynamic_cast<ExistsOrDataParameter*>(param1)->value(),
504
0
                                 dynamic_cast<ExistsOrDataParameter*>(param2)->value());
505
506
0
      case ParameterTypes::lr:
507
0
      case ParameterTypes::ob:
508
         // Exists parameters are equal.
509
0
         return false;
510
511
0
      default:
512
         // Other parameters are not considered.
513
         // Parameters may be added accordingly to RFCs.
514
0
         return false;
515
0
   }
516
0
}
517
518
bool Uri::isSignificantUriParameter(const ParameterTypes::Type type) noexcept
519
0
{
520
0
   return type == ParameterTypes::user ||
521
0
          type == ParameterTypes::ttl ||
522
0
          type == ParameterTypes::method ||
523
0
          type == ParameterTypes::maddr ||
524
0
          type == ParameterTypes::transport;
525
0
}
526
527
bool Uri::isUserRelevant() const
528
0
{
529
0
   checkParsed();
530
0
   return isEqualNoCase(mScheme, Symbols::Sip) ||
531
0
          isEqualNoCase(mScheme, Symbols::Sips) ||
532
0
          isEqualNoCase(mScheme, Symbols::Tel);
533
0
}
534
535
bool
536
Uri::operator==(const Uri& other) const
537
0
{
538
0
   checkParsed();
539
0
   other.checkParsed();
540
541
   // compare hosts
542
0
   if (DnsUtil::isIpV6Address(mHost) &&
543
0
       DnsUtil::isIpV6Address(other.mHost))
544
0
   {
545
      // compare canonicalized IPV6 addresses
546
547
      // update canonicalized if host changed
548
0
      if (!mHostCanonicalized)
549
0
      {
550
0
         mCanonicalHost = DnsUtil::canonicalizeIpV6Address(mHost);
551
0
         mHostCanonicalized=true;
552
0
      }
553
554
      // update canonicalized if host changed
555
0
      if (!other.mHostCanonicalized)
556
0
      {
557
0
         other.mCanonicalHost = DnsUtil::canonicalizeIpV6Address(other.mHost);
558
0
         other.mHostCanonicalized=true;
559
0
      }
560
561
0
      if (mCanonicalHost != other.mCanonicalHost)
562
0
      {
563
0
         return false;
564
0
      }
565
0
   }
566
0
   else
567
0
   {
568
0
      if (!isEqualNoCase(mHost, other.mHost))
569
0
      {
570
0
         return false;
571
0
      }
572
0
   }
573
   
574
   // Case-sensitive user comparison for:
575
   // - sip:/sips: per RFC 3261 sec 19.1.4.
576
   // - urn: because the NID (case-insensitive per RFC 8141) is already
577
   //   normalized to lowercase by Uri::parse() (see comment there), so a
578
   //   plain compare here is correct: NID case differences have already
579
   //   been folded away, and NSS case is preserved and compared as-is.
580
   //   Known deviation: mUser also holds any rq-components/fragment
581
   //   (see the comment in Uri::parse()'s urn branch), which RFC 8141
582
   //   sec 3.1 explicitly excludes from URN equivalence -- so here
583
   //   "urn:example:nss?+rcomponent" != "urn:example:nss", where the RFC
584
   //   would consider them equivalent. Acceptable for SIP routing
585
   //   purposes (this is the same granularity used to compare the
586
   //   sip:/sips: user part above), but not a strict RFC 8141 comparison.
587
   // Every other scheme defaults to case-insensitive.
588
0
   bool userEqual;
589
0
   if (isEqualNoCase(mScheme, Symbols::Sip) || isEqualNoCase(mScheme, Symbols::Sips) ||
590
0
       isEqualNoCase(mScheme, Symbols::Urn))
591
0
   {
592
0
      userEqual = (mUser == other.mUser);
593
0
   }
594
0
   else
595
0
   {
596
0
      userEqual = isEqualNoCase(mUser, other.mUser);
597
0
   }
598
599
0
   if (isEqualNoCase(mScheme, other.mScheme) &&
600
0
       userEqual &&
601
0
       isEqualNoCase(mUserParameters,other.mUserParameters) &&
602
0
       mPassword == other.mPassword &&
603
0
       mPort == other.mPort &&
604
0
       mNetNs == other.mNetNs &&
605
0
       mPath == mPath)
606
0
   {
607
0
      for (ParameterList::const_iterator it = mParameters.begin(); it != mParameters.end(); ++it)
608
0
      {
609
0
         Parameter* otherParam = other.getParameterByEnum((*it)->getType());
610
611
0
         if (Uri::isSignificantUriParameter((*it)->getType()) || otherParam)
612
0
         {
613
0
            if (!Uri::compareUriParametersEqual(*it, otherParam))
614
0
            {
615
0
               return false;
616
0
            }
617
0
         }
618
0
      }         
619
620
      // now check the other way, sigh
621
0
      for (ParameterList::const_iterator it = other.mParameters.begin(); it != other.mParameters.end(); ++it)
622
0
      {
623
0
         Parameter* param = getParameterByEnum((*it)->getType());
624
625
0
         if (Uri::isSignificantUriParameter((*it)->getType()) || param)
626
0
         {
627
0
            if (!Uri::compareUriParametersEqual(*it, param))
628
0
            {
629
0
               return false;
630
0
            }
631
0
         }
632
0
      }
633
0
   }
634
0
   else
635
0
   {
636
0
      return false;
637
0
   }
638
639
0
   OrderUnknownParameters orderUnknown;
640
641
#if defined(__SUNPRO_CC) || defined(WIN32) || defined(__sun__)
642
   // The Solaris Forte STL implementation does not support the
643
   // notion of a list.sort() function taking a BinaryPredicate.
644
   // The hacky workaround is to load the Parameter pointers into
645
   // an STL set which does support an ordering function.
646
647
   typedef std::set<Parameter*, OrderUnknownParameters> ParameterSet;
648
   ParameterSet unA, unB;
649
650
   for (ParameterList::const_iterator i = mUnknownParameters.begin();
651
        i != mUnknownParameters.end(); ++i)
652
   {
653
      unA.insert(*i);
654
   }
655
   for (ParameterList::const_iterator i = other.mUnknownParameters.begin();
656
        i != other.mUnknownParameters.end(); ++i)
657
   {
658
      unB.insert(*i);
659
   }
660
661
   ParameterSet::iterator a = unA.begin();
662
   ParameterSet::iterator b = unB.begin();
663
#else
664
   // .dlb. more efficient to copy to vector for sorting?
665
   // Uri comparison is expensive; consider caching? ugh
666
0
   ParameterList unA = mUnknownParameters;
667
0
   ParameterList unB = other.mUnknownParameters;
668
669
0
   sort(unA.begin(), unA.end(), orderUnknown);
670
0
   sort(unB.begin(), unB.end(), orderUnknown);
671
 
672
0
   ParameterList::iterator a = unA.begin();
673
0
   ParameterList::iterator b = unB.begin();
674
0
#endif
675
676
0
   while(a != unA.end() && b != unB.end())
677
0
   {
678
0
      if (orderUnknown(*a, *b))
679
0
      {
680
0
         ++a;
681
0
      }
682
0
      else if (orderUnknown(*b, *a))
683
0
      {
684
0
         ++b;
685
0
      }
686
0
      else
687
0
      {
688
0
         if (!isEqualNoCase(dynamic_cast<UnknownParameter*>(*a)->value(),
689
0
                            dynamic_cast<UnknownParameter*>(*b)->value()))
690
0
         {
691
0
            return false;
692
0
         }
693
0
         ++a;
694
0
         ++b;
695
0
      }
696
0
   }
697
0
   return true;
698
0
}
699
700
bool 
701
Uri::operator!=(const Uri& other) const
702
0
{
703
0
   return !(*this == other);
704
0
}
705
706
bool
707
Uri::operator<(const Uri& other) const
708
0
{
709
0
   other.checkParsed();
710
0
   checkParsed();
711
0
   if (mUser < other.mUser)
712
0
   {
713
0
      return true;
714
0
   }
715
716
0
   if (mUser > other.mUser)
717
0
   {
718
0
      return false;
719
0
   }
720
721
0
   if (mUserParameters < other.mUserParameters)
722
0
   {
723
0
      return true;
724
0
   }
725
726
0
   if (mUserParameters > other.mUserParameters)
727
0
   {
728
0
      return false;
729
0
   }
730
731
   // !bwc! Canonicalize before we compare! Jeez...
732
0
   if (!mHostCanonicalized)
733
0
   {
734
0
      if(DnsUtil::isIpV6Address(mHost))
735
0
      {
736
0
         mCanonicalHost = DnsUtil::canonicalizeIpV6Address(mHost);
737
0
      }
738
0
      else
739
0
      {
740
0
         mCanonicalHost = mHost;
741
0
         mCanonicalHost.lowercase();
742
0
      }
743
0
      mHostCanonicalized=true;
744
0
   }
745
   
746
0
   if (!other.mHostCanonicalized)
747
0
   {
748
0
      if(DnsUtil::isIpV6Address(other.mHost))
749
0
      {
750
0
         other.mCanonicalHost = DnsUtil::canonicalizeIpV6Address(other.mHost);
751
0
      }
752
0
      else
753
0
      {
754
0
         other.mCanonicalHost = other.mHost;
755
0
         other.mCanonicalHost.lowercase();
756
0
      }
757
0
      other.mHostCanonicalized=true;
758
0
   }
759
760
0
   if (mCanonicalHost < other.mCanonicalHost)
761
0
   {
762
0
      return true;
763
0
   }
764
765
0
   if (mCanonicalHost > other.mCanonicalHost)
766
0
   {
767
0
      return false;
768
0
   }
769
770
0
   if (mPort < other.mPort)
771
0
   {
772
0
      return true;
773
0
   }
774
775
0
   if (mPort > other.mPort)
776
0
   {
777
0
      return false;
778
0
   }
779
780
0
   for (ParameterList::const_iterator it = mParameters.begin(); it != mParameters.end(); ++it)
781
0
      {
782
0
         Parameter* otherParam = other.getParameterByEnum((*it)->getType());
783
784
0
         if (otherParam)
785
0
         {
786
0
            if (Uri::compareUriParametersLessThan(*it, otherParam)) {
787
0
               return true;
788
0
            }
789
790
0
            if (Uri::compareUriParametersLessThan(otherParam, *it)) {
791
0
               return false;
792
0
            }
793
0
         }
794
0
         else if (Uri::isSignificantUriParameter((*it)->getType()))
795
0
         {
796
0
            return true;  // Significant URI params should not be ignored.
797
0
         }
798
0
      }
799
800
   // Sort unknown parameters from both URIs by their name using comparator class.
801
0
   OrderUnknownParameters orderUnknown;
802
803
#if defined(__SUNPRO_CC) || defined(WIN32) || defined(__sun__)
804
   // The Solaris Forte STL implementation does not support the
805
   // notion of a list.sort() function taking a BinaryPredicate.
806
   // The hacky workaround is to load the Parameter pointers into
807
   // an STL set which does support an ordering function.
808
809
   typedef std::set<Parameter*, OrderUnknownParameters> ParameterSet;
810
   ParameterSet thisUriParamList, otherUriParamList;
811
812
   for (ParameterList::const_iterator i = mUnknownParameters.begin();
813
        i != mUnknownParameters.end(); ++i)
814
   {
815
      thisUriParamList.insert(*i);
816
   }
817
   for (ParameterList::const_iterator i = other.mUnknownParameters.begin();
818
        i != other.mUnknownParameters.end(); ++i)
819
   {
820
      otherUriParamList.insert(*i);
821
   }
822
#else
823
0
   ParameterList thisUriParamList = mUnknownParameters;
824
0
   ParameterList otherUriParamList = other.mUnknownParameters;
825
826
0
   sort(thisUriParamList.begin(), thisUriParamList.end(), orderUnknown);
827
0
   sort(otherUriParamList.begin(), otherUriParamList.end(), orderUnknown);
828
0
#endif
829
830
0
   auto thisUriParam = thisUriParamList.begin();
831
0
   auto otherUriParam = otherUriParamList.begin();
832
833
   // Iterate through unknown parameters of both URIs.
834
   // Advance iterators to compare values of parameters with matching names.
835
0
   while(thisUriParam != thisUriParamList.end() && otherUriParam != otherUriParamList.end())
836
0
   {
837
0
      if (orderUnknown(*thisUriParam, *otherUriParam))
838
0
      {
839
         // this < other param name.
840
0
         ++thisUriParam;
841
0
      }
842
0
      else if (orderUnknown(*otherUriParam, *thisUriParam))
843
0
      {
844
         // other < this param name.
845
0
         ++otherUriParam;
846
0
      }
847
0
      else
848
0
      {
849
         // this == other param name.
850
         // Unknown parameter names are the same. Compare their values.
851
0
         const Data& thisParamValue = dynamic_cast<UnknownParameter*>(*thisUriParam)->value();
852
0
         const Data& otherParamValue = dynamic_cast<UnknownParameter*>(*otherUriParam)->value();
853
854
0
         if (isLessThanNoCase(thisParamValue,
855
0
                              otherParamValue))
856
0
         {
857
0
            return true;
858
0
         }
859
860
0
         if (isLessThanNoCase(otherParamValue,
861
0
                              thisParamValue))
862
0
         {
863
0
            return false;
864
0
         }
865
866
         // Move iterators to the next position.
867
0
         ++thisUriParam;
868
0
         ++otherUriParam;
869
0
      }
870
0
   }
871
872
0
   return false;
873
0
}
874
875
bool
876
Uri::aorEqual(const resip::Uri& rhs) const
877
0
{
878
0
   checkParsed();
879
0
   rhs.checkParsed();
880
881
0
   if (!mHostCanonicalized)
882
0
   {
883
0
      if(DnsUtil::isIpV6Address(mHost))
884
0
      {
885
0
         mCanonicalHost = DnsUtil::canonicalizeIpV6Address(mHost);
886
0
      }
887
0
      else
888
0
      {
889
0
         mCanonicalHost = mHost;
890
0
         mCanonicalHost.lowercase();
891
0
      }
892
0
      mHostCanonicalized=true;
893
0
   }
894
   
895
0
   if (!rhs.mHostCanonicalized)
896
0
   {
897
0
      if(DnsUtil::isIpV6Address(rhs.mHost))
898
0
      {
899
0
         rhs.mCanonicalHost = DnsUtil::canonicalizeIpV6Address(rhs.mHost);
900
0
      }
901
0
      else
902
0
      {
903
0
         rhs.mCanonicalHost = rhs.mHost;
904
0
         rhs.mCanonicalHost.lowercase();
905
0
      }
906
0
      rhs.mHostCanonicalized=true;
907
0
   }
908
   
909
0
   return (mUser == rhs.mUser) && (mCanonicalHost == rhs.mCanonicalHost) && (mPort == rhs.mPort) &&
910
0
           isEqualNoCase(mScheme, rhs.mScheme) && (mNetNs == rhs.mNetNs);
911
0
}
912
913
void 
914
Uri::getAorInternal(bool dropScheme, bool addPort, Data& aor) const
915
0
{
916
   // The AOR is an identity/lookup key, so the user part is intentionally
917
   // emitted in canonical (table-escaped) form and is NOT preserved verbatim
918
   // the way encodeParsed()/getAorAsUri() preserve the sender's mUserRaw.
919
   // Canonicalizing here keeps the key stable regardless of how a sender
920
   // escaped it (e.g. "%23" vs a literal '#'), which matters because
921
   // getAorNoPort() feeds auth key comparisons (DigestAuthenticator, etc.)
922
   // and the registration DB is keyed on this form. Do not change this to
923
   // preserve mUserRaw without auditing those key/identity paths.
924
0
   checkParsed();
925
   // canonicalize host
926
927
0
   addPort = addPort && mPort!=0;
928
929
0
   bool hostIsIpV6Address = DnsUtil::isIpV6Address(mHost);
930
0
   if(!mHostCanonicalized)
931
0
   {
932
0
      if (hostIsIpV6Address)
933
0
      {
934
0
         mCanonicalHost = DnsUtil::canonicalizeIpV6Address(mHost);
935
0
      }
936
0
      else
937
0
      {
938
0
         mCanonicalHost = mHost;
939
0
         mCanonicalHost.lowercase();
940
0
      }
941
0
      mHostCanonicalized = true;
942
0
   }
943
944
   // !bwc! Maybe reintroduce caching of aor. (Would use a bool instead of the
945
   // mOldX cruft)
946
   //                                                  @:10000
947
0
   aor.clear();
948
0
   aor.reserve((dropScheme ? 0 : mScheme.size()+1)
949
0
       + mUser.size() + mCanonicalHost.size() + 7);
950
0
   if(!dropScheme)
951
0
   {
952
0
      aor += mScheme;
953
0
      aor += ':';
954
0
   }
955
956
0
   if (!mUser.empty())
957
0
   {
958
0
#ifdef HANDLE_CHARACTER_ESCAPING
959
0
      {
960
0
         oDataStream str(aor);
961
0
         if (isEqualNoCase(mScheme, Symbols::Urn))
962
0
         {
963
0
            mUser.escapeToStream(str, getUrnEncodingTable());
964
0
         }
965
0
         else
966
0
         {
967
0
            mUser.escapeToStream(str, getUserEncodingTable());
968
0
         }
969
0
      }
970
#else
971
      aor += mUser;
972
#endif
973
0
      if(!mCanonicalHost.empty())
974
0
      {
975
0
         aor += Symbols::AT_SIGN;
976
0
      }
977
0
   }
978
979
0
   if(hostIsIpV6Address && addPort)
980
0
   {
981
0
      aor += Symbols::LS_BRACKET;
982
0
      aor += mCanonicalHost;
983
0
      aor += Symbols::RS_BRACKET;
984
0
   }
985
0
   else
986
0
   {
987
0
      aor += mCanonicalHost;
988
0
   }
989
990
0
   if(addPort)
991
0
   {
992
0
      aor += Symbols::COLON;
993
0
      aor += Data(mPort);
994
0
   }
995
0
}
996
997
Data 
998
Uri::getAOR(bool addPort) const
999
0
{
1000
0
   Data result;
1001
0
   getAorInternal(false, addPort, result);
1002
0
   return result;
1003
0
}
1004
1005
bool 
1006
Uri::userIsTelephoneSubscriber() const
1007
0
{
1008
0
   try
1009
0
   {
1010
0
      ParseBuffer pb(mUser);
1011
0
      pb.assertNotEof();
1012
0
      const char* anchor=pb.position();
1013
0
      bool local=false;
1014
0
      if(*pb.position()=='+')
1015
0
      {
1016
         // Might be a global phone number
1017
0
         pb.skipChar();
1018
0
         pb.skipChars(getGlobalNumberTable());
1019
0
      }
1020
0
      else
1021
0
      {
1022
0
         pb.skipChars(getLocalNumberTable());
1023
0
         local=true;
1024
0
      }
1025
1026
0
      Data dialString(pb.data(anchor));
1027
0
      if(dialString.empty())
1028
0
      {
1029
0
         pb.fail(__FILE__, __LINE__, "Dial string is empty.");
1030
0
      }
1031
1032
      // ?bwc? More dial-string checking? For instance, +/ (or simply /) is not 
1033
      // a valid dial-string according to the BNF; the string must contain at 
1034
      // least one actual digit (or in the local number case, one hex digit or 
1035
      // '*' or '#'. Interestingly, this means that stuff like ///*/// is 
1036
      // valid)
1037
1038
      // Dial string looks ok so far; now look for params (there must be a 
1039
      // phone-context param if this is a local number, otherwise there might 
1040
      // or might not be one)
1041
0
      if(local || !pb.eof())
1042
0
      {
1043
         // The only thing that can be here is a ';'. If it does, we're going 
1044
         // to say it is good enough for us. If something in the parameter 
1045
         // string is malformed, it'll get caught when/if 
1046
         // getUserAsTelephoneSubscriber() is called.
1047
0
         pb.skipChar(';');
1048
0
      }
1049
1050
0
      return true;
1051
0
   }
1052
0
   catch(ParseException& /*e*/)
1053
0
   {
1054
0
      return false;
1055
0
   }
1056
0
}
1057
1058
Token 
1059
Uri::getUserAsTelephoneSubscriber() const
1060
0
{
1061
   // !bwc! Ugly. Someday, refactor all this lazy-parser stuff and make it 
1062
   // possible to control ownership explicitly.
1063
   // Set this up as lazy-parsed, to prevent exceptions from being thrown.
1064
0
   HeaderFieldValue temp(mUser.data(), mUser.size());
1065
0
   Token tempToken(temp, Headers::NONE);
1066
   // tempToken does not own the HeaderFieldValue temp, and temp does not own 
1067
   // its buffer.
1068
1069
   // Here's the voodoo; invoking operator= makes a deep copy of the stuff in
1070
   // tempToken, with result owning the memory, and result is in the unparsed 
1071
   // state.
1072
0
   Token result = tempToken;
1073
0
   return result;
1074
0
}
1075
1076
void 
1077
Uri::setUserAsTelephoneSubscriber(const Token& telephoneSubscriber)
1078
0
{
1079
0
   mUser.clear();
1080
0
   oDataStream str(mUser);
1081
0
   str << telephoneSubscriber;
1082
0
   mUserRaw.reset();
1083
0
}
1084
1085
Data
1086
Uri::getAorNoPort() const
1087
0
{
1088
0
   Data result;
1089
0
   getAorInternal(true, false, result);
1090
0
   return result;
1091
0
}
1092
1093
Data
1094
Uri::getAor() const
1095
0
{
1096
0
   Data result;
1097
0
   getAorInternal(true, true, result);
1098
0
   return result;
1099
0
}
1100
1101
Uri 
1102
Uri::getAorAsUri(TransportType transportTypeToRemoveDefaultPort) const
1103
0
{   
1104
   //.dcm. -- tel conversion?
1105
0
   checkParsed();
1106
0
   Uri ret;
1107
0
   ret.scheme() = mScheme;
1108
0
   ret.user() = mUser;
1109
   // Carry the as-received user bytes so a derived URI that reaches the wire
1110
   // (e.g. a Route built from the AOR) preserves the sender's escaping too.
1111
0
   if (mUserRaw)
1112
0
   {
1113
0
      ret.mUserRaw.reset(new Data(*mUserRaw));
1114
0
   }
1115
0
   ret.host() = mHost;
1116
1117
   // Remove any default ports (if required)
1118
0
   if(transportTypeToRemoveDefaultPort == UDP || 
1119
0
       transportTypeToRemoveDefaultPort == TCP)
1120
0
   {
1121
0
      if(mPort != Symbols::DefaultSipPort)
1122
0
      {
1123
0
         ret.port() = mPort;
1124
0
      }
1125
0
   }
1126
0
   else if (transportTypeToRemoveDefaultPort == TLS || 
1127
0
            transportTypeToRemoveDefaultPort == DTLS)
1128
0
   {
1129
0
      if(mPort != Symbols::DefaultSipsPort)
1130
0
      {
1131
0
         ret.port() = mPort;
1132
0
      }
1133
0
   }
1134
0
   else
1135
0
   {
1136
0
      ret.port() = mPort;
1137
0
   }
1138
1139
0
   return ret;
1140
0
}
1141
1142
#ifdef HANDLE_CHARACTER_ESCAPING
1143
// Decodes [start, pb.position()) into `user`, capturing the as-received
1144
// bytes into `userRaw` (only if a '%' escape is present) so encodeParsed()
1145
// can re-emit them verbatim instead of losing the sender's original
1146
// escaping. Shared by the sip:/sips: and urn: user-parsing below -- both
1147
// need the exact same "scan for '%', then dataUnescaped" dance.
1148
static void
1149
decodeUserPreservingEscapes(ParseBuffer& pb, const char* start,
1150
                             Data& user, std::unique_ptr<Data>& userRaw)
1151
1.20k
{
1152
1.20k
   const char* userEnd = pb.position();
1153
1.20k
   bool userHasEscape = false;
1154
11.3M
   for (const char* p = start; p < userEnd; ++p)
1155
11.3M
   {
1156
11.3M
      if (*p == Symbols::PERCENT[0])
1157
388
      {
1158
388
         userHasEscape = true;
1159
388
         break;
1160
388
      }
1161
11.3M
   }
1162
1.20k
   pb.dataUnescaped(user, start);
1163
   // Capture the as-received bytes only after the decode succeeds -- it can
1164
   // throw on a malformed escape, and userRaw must never hold bytes that
1165
   // fail to decode, so the encode-path re-decode cannot throw. userRaw
1166
   // then always decodes back to the user just produced.
1167
1.20k
   if (userHasEscape)
1168
206
   {
1169
206
      userRaw.reset(new Data(start, (Data::size_type)(userEnd - start)));
1170
206
   }
1171
1.20k
}
1172
#endif
1173
1174
void
1175
Uri::parse(ParseBuffer& pb)
1176
19.6k
{
1177
19.6k
   pb.skipWhitespace();
1178
19.6k
   const char* start = pb.position();
1179
1180
   // Cleared up front so a path that sets no user part leaves no stale raw.
1181
19.6k
   mUserRaw.reset();
1182
1183
   // Relative URLs (typically HTTP) start with a slash.  These
1184
   // are seen when parsing the WebSocket handshake.
1185
19.6k
   if (*pb.position() == Symbols::SLASH[0])
1186
752
   {
1187
752
      mScheme.clear();
1188
752
      pb.skipToOneOf("?;", ParseBuffer::Whitespace);
1189
752
      pb.data(mPath, start);
1190
752
      if (!pb.eof() && !ParseBuffer::oneOf(*pb.position(), ParseBuffer::Whitespace))
1191
541
      {
1192
541
         parseParameters(pb);
1193
541
      }
1194
752
      return;
1195
752
   }
1196
1197
18.8k
   pb.skipToOneOf(":@");
1198
1199
18.8k
   pb.assertNotEof();
1200
1201
18.8k
   pb.data(mScheme, start);
1202
18.8k
   pb.skipChar(Symbols::COLON[0]);
1203
18.8k
   mScheme.schemeLowercase();
1204
1205
   // NID:NSS plus any rq-components ("?+"/"?=") and fragment ("#") is
1206
   // captured as one opaque blob in mUser; no mUserParameters equivalent
1207
   // (RFC 8141 has none).
1208
18.8k
   if (mScheme==Symbols::Urn)
1209
576
   {
1210
576
      const char* anchor = pb.position();
1211
576
      if (mIsBetweenAngleQuotes)
1212
17
      {
1213
         // Inside "<...>" the only terminator is '>' (SIP requires angle
1214
         // brackets exactly to avoid ';'/'?'/',' clashing with NameAddr
1215
         // params -- RFC 3261 sec 20 -- so within brackets those chars are
1216
         // legal NSS content and must not be treated as delimiters).
1217
17
         static std::bitset<256> delimiter=Data::toBitset("\r\n\t >");
1218
17
         pb.skipToOneOf(delimiter);
1219
17
      }
1220
559
      else if (mIsBareAddrSpec)
1221
244
      {
1222
         // Bare (unbracketed) URI inside a header value (e.g. To/From
1223
         // without "<...>"), flagged by NameAddr::parse(): stop at
1224
         // ';'/'?'/',' too, since NameAddr parameters (";tag=...") may
1225
         // follow directly and RFC 8141 gives no way to tell them apart
1226
         // from NSS content here. Per RFC 3261 sec 20, a producer whose
1227
         // NSS needs these characters must use "<...>" instead, where the
1228
         // permissive rule above still applies.
1229
244
         static std::bitset<256> delimiter=Data::toBitset("\r\n\t ;?,");
1230
244
         pb.skipToOneOf(delimiter);
1231
244
      }
1232
315
      else
1233
315
      {
1234
         // Every other context: a Request-URI (RequestLine, never
1235
         // bracketed but with nothing that can follow except whitespace
1236
         // then SIP-Version), a standalone Uri built directly from a
1237
         // string, or any other direct caller. ';'/'?'/',' here are legal
1238
         // NSS content, same as the bracketed case above.
1239
315
         pb.skipToOneOf(ParseBuffer::Whitespace);
1240
315
      }
1241
576
#ifdef HANDLE_CHARACTER_ESCAPING
1242
      // Decode %XX so user() returns the logical value, as for sip:/sips:.
1243
      // But '#'/'?' are structural when unescaped (fragment/rq-components),
1244
      // so a received "%23"/"%3F" (escaped data) and a literal "#"/"?"
1245
      // (real separator) must not collapse to the same mUser and then
1246
      // re-encode with the wrong form -- decodeUserPreservingEscapes()
1247
      // keeps the as-received bytes in mUserRaw for that case.
1248
576
      decodeUserPreservingEscapes(pb, anchor, mUser, mUserRaw);
1249
#else
1250
      pb.data(mUser, anchor);
1251
#endif
1252
      // RFC 8141 sec 2: NID = alphanum *(alphanum/"-") alphanum, 2-32
1253
      // chars, and the NSS must be non-empty; sec 5.1: the NID must not be
1254
      // "urn" itself (nonsensical/reserved). Reject anything else here so
1255
      // a malformed urn: fails to parse instead of silently reaching the
1256
      // application (e.g. DUM) looking like a well-formed one.
1257
576
      const Data::size_type sep = mUser.find(Symbols::COLON);
1258
576
      if (sep == Data::npos)
1259
72
      {
1260
72
         pb.fail(__FILE__, __LINE__, "urn: missing NID:NSS separator.");
1261
72
      }
1262
576
      if (sep < 2 || sep > 32)
1263
73
      {
1264
73
         pb.fail(__FILE__, __LINE__, "urn: NID must be 2-32 characters.");
1265
73
      }
1266
3.42k
      for (Data::size_type i = 0; i < sep; ++i)
1267
2.85k
      {
1268
2.85k
         const unsigned char c = (unsigned char)mUser[i];
1269
         // Explicit ASCII range, not isalnum(): RFC 8141's NID ABNF is
1270
         // ASCII-only, but isalnum() follows the process-wide C locale,
1271
         // so a non-C locale (common in embedded/softswitch apps that
1272
         // call setlocale() for logging/i18n) would accept 8-bit
1273
         // characters here that RFC 8141 does not allow.
1274
2.85k
         const bool isAsciiAlnum = (c >= '0' && c <= '9') ||
1275
1.95k
                                   (c >= 'A' && c <= 'Z') ||
1276
1.27k
                                   (c >= 'a' && c <= 'z');
1277
2.85k
         if (!isAsciiAlnum && !(c == '-' && i > 0 && i < sep - 1))
1278
162
         {
1279
162
            pb.fail(__FILE__, __LINE__, "urn: NID has an invalid character.");
1280
162
         }
1281
2.85k
      }
1282
576
      if (sep + 1 >= mUser.size())
1283
72
      {
1284
72
         pb.fail(__FILE__, __LINE__, "urn: NSS must not be empty.");
1285
72
      }
1286
576
      if (isEqualNoCase(mUser.substr(0, sep), Symbols::Urn))
1287
7
      {
1288
7
         pb.fail(__FILE__, __LINE__, "urn: NID must not be \"urn\".");
1289
7
      }
1290
1291
      // RFC 8141 sec 2.2: the NID is case-insensitive. Normalize it to
1292
      // lowercase here, the same way schemeLowercase() already normalizes
1293
      // the scheme, so operator==, operator<, the hash function and
1294
      // getAorInternal() all agree on urn: equality without needing a
1295
      // urn-specific comparator.
1296
      // NB: this only runs at parse() time, so a hand-built Uri (user()
1297
      // set directly) is not validated/normalized -- same accepted
1298
      // limitation as the scheme case-sensitivity noted on
1299
      // getAorInternal()/encodeParsed().
1300
576
      {
1301
576
         Data nid(mUser.substr(0, sep));
1302
576
         nid.lowercase();
1303
576
         mUser = nid + mUser.substr(sep);
1304
576
      }
1305
      // mUserRaw is deliberately left untouched (still the exact bytes
1306
      // received): the validation above runs on the decoded mUser, so a
1307
      // NID could in principle hide a gratuitous, unnecessary %-escape
1308
      // (e.g. "urn:EX%41MPLE:nss") that isn't reflected at the same byte
1309
      // offset in mUserRaw -- rewriting mUserRaw's NID prefix in place,
1310
      // like above, would silently corrupt it in that case. Leaving it
1311
      // untouched is simpler and always correct: encodeParsed()'s
1312
      // decodedUserRaw==mUser check already re-decodes mUserRaw and falls
1313
      // back to escaping mUser fresh whenever they no longer match (e.g.
1314
      // because of this normalization step here), which is exactly the
1315
      // desired outcome whenever the NID's original casing has changed.
1316
576
      return;
1317
576
   }
1318
1319
18.2k
   if (mScheme==Symbols::Tel)
1320
47
   {
1321
47
      const char* anchor = pb.position();
1322
47
      static std::bitset<256> delimiter=Data::toBitset("\r\n\t ;>");
1323
47
      pb.skipToOneOf(delimiter);
1324
47
      pb.data(mUser, anchor);
1325
47
      if (!pb.eof() && *pb.position() == Symbols::SEMI_COLON[0])
1326
17
      {
1327
17
         anchor = pb.skipChar();
1328
17
         pb.skipToOneOf(ParseBuffer::Whitespace, Symbols::RA_QUOTE);
1329
17
         pb.data(mUserParameters, anchor);
1330
17
      }
1331
47
      return;
1332
47
   }
1333
   
1334
18.2k
   start = pb.position();
1335
18.2k
   static std::bitset<256> userPortOrPasswordDelim(Data::toBitset("@:\""));
1336
   // stop at double-quote to prevent matching an '@' in a quoted string param. 
1337
18.2k
   pb.skipToOneOf(userPortOrPasswordDelim);
1338
18.2k
   if (!pb.eof())
1339
3.42k
   {
1340
3.42k
      const char* atSign=0;
1341
3.42k
      if (*pb.position() == Symbols::COLON[0])
1342
2.59k
      {
1343
         // Either a password, or a port
1344
2.59k
         const char* afterColon = pb.skipChar();
1345
2.59k
         pb.skipToOneOf("@\"");
1346
2.59k
         if(!pb.eof() && *pb.position() == Symbols::AT_SIGN[0])
1347
230
         {
1348
230
            atSign=pb.position();
1349
            // password
1350
230
#ifdef HANDLE_CHARACTER_ESCAPING
1351
230
            pb.dataUnescaped(mPassword, afterColon);
1352
#else
1353
            pb.data(mPassword, afterColon);
1354
#endif
1355
230
            pb.reset(afterColon-1);
1356
230
         }
1357
2.36k
         else
1358
2.36k
         {
1359
            // port. No user part.
1360
2.36k
            pb.reset(start);
1361
2.36k
         }
1362
2.59k
      }
1363
826
      else if(*pb.position() == Symbols::AT_SIGN[0])
1364
474
      {
1365
474
         atSign=pb.position();
1366
474
      }
1367
352
      else
1368
352
      {
1369
         // Only a hostpart
1370
352
         pb.reset(start);
1371
352
      }
1372
1373
3.42k
      if(atSign)
1374
628
      {
1375
628
#ifdef HANDLE_CHARACTER_ESCAPING
1376
         // The range dataUnescaped decodes here is exactly [start, position),
1377
         // i.e. up to ':' before a password, else '@' -- decodeUserPreservingEscapes()
1378
         // scans it for an escape and keeps the as-received bytes in mUserRaw.
1379
628
         decodeUserPreservingEscapes(pb, start, mUser, mUserRaw);
1380
#else
1381
         pb.data(mUser, start);
1382
#endif
1383
628
         pb.reset(atSign);
1384
628
         start = pb.skipChar();
1385
628
      }
1386
3.42k
   }
1387
14.8k
   else
1388
14.8k
   {
1389
14.8k
      pb.reset(start);
1390
14.8k
   }
1391
1392
18.2k
   if (pb.eof())
1393
484
   {
1394
484
      return;
1395
484
   }
1396
1397
17.7k
   mHostCanonicalized=false;
1398
17.7k
   static std::bitset<256> hostDelimiter(Data::toBitset("\r\n\t :;?>"));
1399
17.7k
   if (*start == '[')
1400
141
   {
1401
141
      start = pb.skipChar();
1402
141
      pb.skipToChar(']');
1403
141
      pb.data(mHost, start);
1404
141
      mCanonicalHost = DnsUtil::canonicalizeIpV6Address(mHost);
1405
141
      if (mCanonicalHost.empty())
1406
42
      {
1407
         // .bwc. So the V6 addy is garbage.
1408
42
         throw ParseException("Unparsable V6 address (note, this might"
1409
42
                                    " be unparsable because IPV6 support is not"
1410
42
                                    " enabled)","Uri",__FILE__,
1411
42
                                       __LINE__);
1412
42
      }
1413
99
      mHostCanonicalized = true;
1414
99
      pb.skipChar();
1415
99
      pb.skipToOneOf(hostDelimiter);
1416
99
   }
1417
17.6k
   else
1418
17.6k
   {
1419
17.6k
      pb.skipToOneOf(hostDelimiter);
1420
17.6k
      pb.data(mHost, start);
1421
17.6k
   }
1422
1423
17.7k
   if (!pb.eof() && *pb.position() == ':')
1424
412
   {
1425
412
      start = pb.skipChar();
1426
412
      mPort = pb.uInt32();
1427
412
   }
1428
17.2k
   else
1429
17.2k
   {
1430
17.2k
      mPort = 0;
1431
17.2k
   }
1432
1433
17.7k
   parseParameters(pb);
1434
1435
17.7k
   if (!pb.eof() && *pb.position() == Symbols::QUESTION[0])
1436
2.51k
   {
1437
2.51k
      const char* anchor = pb.position();
1438
1439
2.51k
      if (mIsBetweenAngleQuotes)
1440
56
      {
1441
         // Embedded headers will either end at the angle bracket (when Uri is in a NameAddr that uses angle 
1442
         // brackets) or at a semi-colon (when Uri is in a NameAddr that doesn't use angle brackets and has 
1443
         // NameAddr parameters following the embedded headers), or in Whitespace.
1444
         // We used to just look for either of the 3 terminators, however to be more tolerant of endpoints 
1445
         // that do not properly escape ;'s in the embedded headers, we relax the rules, only when the uri
1446
         // falls between angle quotes/brackets - in this case we will allow non-escaped semi-colons by only
1447
         // looking for > and whitespace as a terminator.
1448
56
         pb.skipToOneOf(">", ParseBuffer::Whitespace);
1449
56
      }
1450
2.46k
      else
1451
2.46k
      {
1452
2.46k
         pb.skipToOneOf(">;", ParseBuffer::Whitespace);
1453
2.46k
      }
1454
1455
2.51k
      if(!mEmbeddedHeadersText.get()) mEmbeddedHeadersText.reset(new Data);
1456
2.51k
      pb.data(*mEmbeddedHeadersText, anchor);
1457
2.51k
   }
1458
17.7k
}
1459
1460
ParserCategory*
1461
Uri::clone() const
1462
0
{
1463
0
   return new Uri(*this);
1464
0
}
1465
1466
ParserCategory*
1467
Uri::clone(void* location) const
1468
0
{
1469
0
   return new (location) Uri(*this);
1470
0
}
1471
1472
ParserCategory*
1473
Uri::clone(PoolBase* pool) const
1474
0
{
1475
0
   return new (pool) Uri(*this);
1476
0
}
1477
1478
void Uri::setUriUserEncoding(unsigned char c, bool encode) 
1479
0
{
1480
0
   getUserEncodingTable()[c] = encode; 
1481
0
}
1482
1483
void Uri::setUriPasswordEncoding(unsigned char c, bool encode)
1484
0
{
1485
0
   getPasswordEncodingTable()[c] = encode;
1486
0
}
1487
1488
void Uri::setUriUrnEncoding(unsigned char c, bool encode)
1489
0
{
1490
0
   getUrnEncodingTable()[c] = encode;
1491
0
}
1492
1493
// should not encode user parameters unless its a tel?
1494
EncodeStream& 
1495
Uri::encodeParsed(EncodeStream& str) const
1496
0
{
1497
   // Relative URIs may not have the scheme
1498
0
   if (!mScheme.empty())
1499
0
   {
1500
0
      str << mScheme << Symbols::COLON;
1501
0
   }
1502
1503
0
   if (!mUser.empty())
1504
0
   {
1505
0
#ifdef HANDLE_CHARACTER_ESCAPING
1506
      // urn: uses its own table (doesn't escape ':', '@', ';', '?', '#',
1507
      // sub-delims -- RFC 8141); every other scheme uses the sip:/sips:
1508
      // user table.
1509
0
      const EncodingTable& table = isEqualNoCase(mScheme, Symbols::Urn)
1510
0
         ? getUrnEncodingTable() : getUserEncodingTable();
1511
0
      if (mUserRaw)
1512
0
      {
1513
         // Emit the as-received bytes verbatim while they still decode (via the
1514
         // same dataUnescaped as parse) to the current mUser, so the sender's
1515
         // escaping (e.g. %23) survives regardless of the encoding table; a
1516
         // post-parse edit breaks the match and falls back to table escaping.
1517
         // Cost: re-decodes and compares on the encode path for every
1518
         // %-containing user part (inline Data buffer avoids a heap alloc for
1519
         // short values; unescaped users skip this branch).
1520
0
         Data decodedUserRaw;
1521
0
         ParseBuffer pb(mUserRaw->data(), mUserRaw->size());
1522
0
         const char* anchor = pb.position();
1523
0
         pb.skipToEnd();
1524
0
         pb.dataUnescaped(decodedUserRaw, anchor);
1525
0
         if (decodedUserRaw == mUser)
1526
0
         {
1527
0
            str << *mUserRaw;
1528
0
         }
1529
0
         else
1530
0
         {
1531
0
            mUser.escapeToStream(str, table);
1532
0
         }
1533
0
      }
1534
0
      else
1535
0
      {
1536
0
         mUser.escapeToStream(str, table);
1537
0
      }
1538
#else
1539
      str << mUser;
1540
#endif
1541
0
      if (!mUserParameters.empty())
1542
0
      {
1543
0
         str << Symbols::SEMI_COLON[0] << mUserParameters;
1544
0
      }
1545
0
      if (!mPassword.empty())
1546
0
      {
1547
0
         str << Symbols::COLON;
1548
0
#ifdef HANDLE_CHARACTER_ESCAPING
1549
0
         mPassword.escapeToStream(str, getPasswordEncodingTable());
1550
#else
1551
         str << mPassword;
1552
#endif
1553
0
      }
1554
0
   }
1555
0
   if (!mHost.empty())
1556
0
   {
1557
0
     if (!mUser.empty())
1558
0
     {
1559
0
       str << Symbols::AT_SIGN;
1560
0
     }
1561
0
     if (DnsUtil::isIpV6Address(mHost))
1562
0
     {
1563
0
        str << '[' << mHost << ']';
1564
0
     }
1565
0
     else
1566
0
     {
1567
0
        str << mHost;
1568
0
     }
1569
0
   }
1570
0
   if (mPort != 0)
1571
0
   {
1572
0
      str << Symbols::COLON << mPort;
1573
0
   }
1574
0
   if (!mPath.empty())
1575
0
   {
1576
0
      str << mPath;
1577
0
   }
1578
0
   encodeParameters(str);
1579
0
   encodeEmbeddedHeaders(str);
1580
1581
0
   return str;
1582
0
}
1583
1584
SipMessage&
1585
Uri::embedded()
1586
6.64k
{
1587
6.64k
   checkParsed();
1588
6.64k
   if (mEmbeddedHeaders.get() == 0)
1589
3.31k
   {
1590
3.31k
      this->mEmbeddedHeaders.reset(new SipMessage());
1591
3.31k
      if (mEmbeddedHeadersText.get() && !mEmbeddedHeadersText->empty())
1592
1.23k
      {
1593
1.23k
         ParseBuffer pb(mEmbeddedHeadersText->data(), mEmbeddedHeadersText->size());
1594
1.23k
         this->parseEmbeddedHeaders(pb);
1595
1.23k
      }
1596
3.31k
   }
1597
1598
6.64k
   return *mEmbeddedHeaders;
1599
6.64k
}
1600
1601
const SipMessage&
1602
Uri::embedded() const
1603
0
{
1604
0
   Uri* ncthis = const_cast<Uri*>(this);
1605
0
   return ncthis->embedded();
1606
0
}
1607
1608
static const Data bodyData("Body");
1609
void
1610
Uri::parseEmbeddedHeaders(ParseBuffer& pb)
1611
1.23k
{
1612
1.23k
   DebugLog(<< "Uri::parseEmbeddedHeaders");
1613
1.23k
   if (!pb.eof() && *pb.position() == Symbols::QUESTION[0])
1614
1.23k
   {
1615
1.23k
      pb.skipChar();
1616
1.23k
   }
1617
1618
1.23k
   const char* anchor;
1619
1.23k
   Data headerName;
1620
1.23k
   Data headerContents;
1621
1622
1.23k
   bool first = true;
1623
843k
   while (!pb.eof())
1624
841k
   {
1625
841k
      if (first)
1626
1.19k
      {
1627
1.19k
         first = false;
1628
1.19k
      }
1629
840k
      else
1630
840k
      {
1631
840k
         pb.skipChar(Symbols::AMPERSAND[0]);
1632
840k
      }
1633
1634
841k
      anchor = pb.position();
1635
841k
      pb.skipToChar(Symbols::EQUALS[0]);
1636
841k
      pb.data(headerName, anchor);
1637
      // .dlb. in theory, need to decode header name
1638
1639
841k
      anchor = pb.skipChar(Symbols::EQUALS[0]);
1640
841k
      pb.skipToChar(Symbols::AMPERSAND[0]);
1641
841k
      pb.data(headerContents, anchor);
1642
1643
841k
      unsigned int len;
1644
841k
      char* decodedContents = Embedded::decode(headerContents, len);
1645
841k
      mEmbeddedHeaders->addBuffer(decodedContents);
1646
1647
841k
      if (isEqualNoCase(bodyData, headerName))
1648
4.78k
      {
1649
4.78k
         mEmbeddedHeaders->setBody(decodedContents, len); 
1650
4.78k
      }
1651
837k
      else
1652
837k
      {
1653
837k
         DebugLog(<< "Uri::parseEmbeddedHeaders(" << headerName << ", " << Data(decodedContents, len) << ")");
1654
837k
         mEmbeddedHeaders->addHeader(Headers::getType(headerName.data(), headerName.size()),
1655
837k
                                     headerName.data(), (int)headerName.size(),
1656
837k
                                     decodedContents, len);
1657
837k
      }
1658
841k
   }
1659
1.23k
}
1660
1661
EncodeStream& 
1662
Uri::encodeEmbeddedHeaders(EncodeStream& str) const
1663
0
{
1664
0
   if (mEmbeddedHeaders.get())
1665
0
   {
1666
0
      mEmbeddedHeaders->encodeEmbedded(str);
1667
0
   }
1668
0
   else if(mEmbeddedHeadersText.get())
1669
0
   {
1670
      // never decoded
1671
0
      str << *mEmbeddedHeadersText;
1672
0
   }
1673
0
   return str;
1674
0
}
1675
1676
Data 
1677
Uri::toString() const
1678
0
{
1679
0
   Data out;
1680
0
   {
1681
0
      oDataStream dataStream(out);
1682
0
      this->encodeParsed(dataStream);
1683
0
   }
1684
0
   return out;
1685
0
}
1686
1687
ParameterTypes::Factory Uri::ParameterFactories[ParameterTypes::MAX_PARAMETER]={0};
1688
1689
Parameter* 
1690
Uri::createParam(ParameterTypes::Type type, ParseBuffer& pb, const std::bitset<256>& terminators, PoolBase* pool)
1691
25.2k
{
1692
25.2k
   if(type > ParameterTypes::UNKNOWN && type < ParameterTypes::MAX_PARAMETER && ParameterFactories[type])
1693
20.4k
   {
1694
20.4k
      return ParameterFactories[type](type, pb, terminators, pool);
1695
20.4k
   }
1696
4.77k
   return 0;
1697
25.2k
}
1698
1699
bool 
1700
Uri::exists(const Param<Uri>& paramType) const
1701
0
{
1702
0
    checkParsed();
1703
0
    bool ret = getParameterByEnum(paramType.getTypeNum()) != NULL;
1704
0
    return ret;
1705
0
}
1706
1707
void 
1708
Uri::remove(const Param<Uri>& paramType)
1709
0
{
1710
0
    checkParsed();
1711
0
    removeParameterByEnum(paramType.getTypeNum());
1712
0
}
1713
1714
#define defineParam(_enum, _name, _type, _RFC_ref_ignored)                                                      \
1715
_enum##_Param::DType&                                                                                           \
1716
0
Uri::param(const _enum##_Param& paramType)                                                           \
1717
0
{                                                                                                               \
1718
0
   checkParsed();                                                                                               \
1719
0
   _enum##_Param::Type* p =                                                                                     \
1720
0
      static_cast<_enum##_Param::Type*>(getParameterByEnum(paramType.getTypeNum()));                            \
1721
0
   if (!p)                                                                                                      \
1722
0
   {                                                                                                            \
1723
0
      p = new _enum##_Param::Type(paramType.getTypeNum());                                                      \
1724
0
      mParameters.push_back(p);                                                                                 \
1725
0
   }                                                                                                            \
1726
0
   return p->value();                                                                                           \
1727
0
}                                                                                                               \
Unexecuted instantiation: resip::Uri::param(resip::ob_Param const&)
Unexecuted instantiation: resip::Uri::param(resip::gr_Param const&)
Unexecuted instantiation: resip::Uri::param(resip::comp_Param const&)
Unexecuted instantiation: resip::Uri::param(resip::duration_Param const&)
Unexecuted instantiation: resip::Uri::param(resip::lr_Param const&)
Unexecuted instantiation: resip::Uri::param(resip::maddr_Param const&)
Unexecuted instantiation: resip::Uri::param(resip::method_Param const&)
Unexecuted instantiation: resip::Uri::param(resip::transport_Param const&)
Unexecuted instantiation: resip::Uri::param(resip::ttl_Param const&)
Unexecuted instantiation: resip::Uri::param(resip::user_Param const&)
Unexecuted instantiation: resip::Uri::param(resip::extension_Param const&)
Unexecuted instantiation: resip::Uri::param(resip::sigcompId_Param const&)
Unexecuted instantiation: resip::Uri::param(resip::rinstance_Param const&)
Unexecuted instantiation: resip::Uri::param(resip::addTransport_Param const&)
Unexecuted instantiation: resip::Uri::param(resip::wsSrcIp_Param const&)
Unexecuted instantiation: resip::Uri::param(resip::wsSrcPort_Param const&)
1728
                                                                                                                \
1729
const _enum##_Param::DType&                                                                                     \
1730
0
Uri::param(const _enum##_Param& paramType) const                                                     \
1731
0
{                                                                                                               \
1732
0
   checkParsed();                                                                                               \
1733
0
   _enum##_Param::Type* p =                                                                                     \
1734
0
      static_cast<_enum##_Param::Type*>(getParameterByEnum(paramType.getTypeNum()));                            \
1735
0
   if (!p)                                                                                                      \
1736
0
   {                                                                                                            \
1737
0
      InfoLog(<< "Missing parameter " _name " " << ParameterTypes::ParameterNames[paramType.getTypeNum()]);     \
1738
0
      DebugLog(<< *this);                                                                                       \
1739
0
      throw Exception("Missing parameter " _name, __FILE__, __LINE__);                                          \
1740
0
   }                                                                                                            \
1741
0
   return p->value();                                                                                           \
1742
0
}
Unexecuted instantiation: resip::Uri::param(resip::ob_Param const&) const
Unexecuted instantiation: resip::Uri::param(resip::gr_Param const&) const
Unexecuted instantiation: resip::Uri::param(resip::comp_Param const&) const
Unexecuted instantiation: resip::Uri::param(resip::duration_Param const&) const
Unexecuted instantiation: resip::Uri::param(resip::lr_Param const&) const
Unexecuted instantiation: resip::Uri::param(resip::maddr_Param const&) const
Unexecuted instantiation: resip::Uri::param(resip::method_Param const&) const
Unexecuted instantiation: resip::Uri::param(resip::transport_Param const&) const
Unexecuted instantiation: resip::Uri::param(resip::ttl_Param const&) const
Unexecuted instantiation: resip::Uri::param(resip::user_Param const&) const
Unexecuted instantiation: resip::Uri::param(resip::extension_Param const&) const
Unexecuted instantiation: resip::Uri::param(resip::sigcompId_Param const&) const
Unexecuted instantiation: resip::Uri::param(resip::rinstance_Param const&) const
Unexecuted instantiation: resip::Uri::param(resip::addTransport_Param const&) const
Unexecuted instantiation: resip::Uri::param(resip::wsSrcIp_Param const&) const
Unexecuted instantiation: resip::Uri::param(resip::wsSrcPort_Param const&) const
1743
1744
defineParam(ob,"ob",ExistsParameter,"RFC 5626");
1745
defineParam(gr, "gr", ExistsOrDataParameter, "RFC 5627");
1746
defineParam(comp, "comp", DataParameter, "RFC 3486");
1747
defineParam(duration, "duration", UInt32Parameter, "RFC 4240");
1748
defineParam(lr, "lr", ExistsParameter, "RFC 3261");
1749
defineParam(maddr, "maddr", DataParameter, "RFC 3261");
1750
defineParam(method, "method", DataParameter, "RFC 3261");
1751
defineParam(transport, "transport", DataParameter, "RFC 3261");
1752
defineParam(ttl, "ttl", UInt32Parameter, "RFC 3261");
1753
defineParam(user, "user", DataParameter, "RFC 3261, 4967");
1754
defineParam(extension, "ext", DataParameter, "RFC 3966"); // Token is used when ext is a user-parameter
1755
defineParam(sigcompId, "sigcomp-id", QuotedDataParameter, "RFC 5049");
1756
defineParam(rinstance, "rinstance", DataParameter, "proprietary (resip)");
1757
defineParam(addTransport, "addTransport", ExistsParameter, "RESIP INTERNAL");
1758
defineParam(wsSrcIp, "ws-src-ip", DataParameter, "RESIP INTERNAL (WebSocket)");
1759
defineParam(wsSrcPort, "ws-src-port", UInt32Parameter, "RESIP INTERNAL (WebSocket)");
1760
1761
#undef defineParam
1762
1763
HashValueImp(resip::Uri, resip::Data::from(data).hash());
1764
1765
/* ====================================================================
1766
 * The Vovida Software License, Version 1.0 
1767
 * 
1768
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
1769
 * 
1770
 * Redistribution and use in source and binary forms, with or without
1771
 * modification, are permitted provided that the following conditions
1772
 * are met:
1773
 * 
1774
 * 1. Redistributions of source code must retain the above copyright
1775
 *    notice, this list of conditions and the following disclaimer.
1776
 * 
1777
 * 2. Redistributions in binary form must reproduce the above copyright
1778
 *    notice, this list of conditions and the following disclaimer in
1779
 *    the documentation and/or other materials provided with the
1780
 *    distribution.
1781
 * 
1782
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1783
 *    and "Vovida Open Communication Application Library (VOCAL)" must
1784
 *    not be used to endorse or promote products derived from this
1785
 *    software without prior written permission. For written
1786
 *    permission, please contact vocal@vovida.org.
1787
 *
1788
 * 4. Products derived from this software may not be called "VOCAL", nor
1789
 *    may "VOCAL" appear in their name, without prior written
1790
 *    permission of Vovida Networks, Inc.
1791
 * 
1792
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1793
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1794
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1795
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
1796
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1797
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1798
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1799
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1800
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1801
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1802
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1803
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1804
 * DAMAGE.
1805
 * 
1806
 * ====================================================================
1807
 * 
1808
 * This software consists of voluntary contributions made by Vovida
1809
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1810
 * Inc.  For more information on Vovida Networks, Inc., please see
1811
 * <http://www.vovida.org/>.
1812
 *
1813
 */