Coverage Report

Created: 2026-05-24 06:57

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
   return true;
33
2
}
34
35
const bool Uri::tablesMightBeInitialized(initAllTables());
36
37
Uri::Uri(PoolBase* pool) 
38
25.5k
   : ParserCategory(pool),
39
25.5k
     mScheme(Data::Share, Symbols::DefaultSipScheme),
40
25.5k
     mPort(0),
41
25.5k
     mHostCanonicalized(false),
42
25.5k
     mIsBetweenAngleQuotes(false)
43
25.5k
{
44
25.5k
}
45
46
Uri::Uri(const HeaderFieldValue& hfv, Headers::Type type, PoolBase* pool) :
47
6.23k
   ParserCategory(hfv, type, pool),
48
6.23k
   mPort(0),
49
6.23k
   mHostCanonicalized(false),
50
6.23k
   mIsBetweenAngleQuotes(false)
51
6.23k
{}
52
53
54
static const Data parseContext("Uri constructor");
55
Uri::Uri(const Data& data)
56
0
   : ParserCategory(), 
57
0
     mScheme(Symbols::DefaultSipScheme),
58
0
     mPort(0),
59
0
     mHostCanonicalized(false),
60
0
     mIsBetweenAngleQuotes(false)
61
0
{
62
0
   HeaderFieldValue hfv(data.data(), data.size());
63
   // must copy because parse creates overlays
64
0
   Uri tmp(hfv, Headers::UNKNOWN);
65
0
   tmp.checkParsed();
66
0
   *this = tmp;
67
0
}
68
69
Uri::Uri(const Uri& rhs,
70
         PoolBase* pool)
71
0
   : ParserCategory(rhs, pool),
72
0
     mScheme(rhs.mScheme),
73
0
     mHost(rhs.mHost),
74
0
     mUser(rhs.mUser),
75
0
     mUserParameters(rhs.mUserParameters),
76
0
     mPort(rhs.mPort),
77
0
     mPassword(rhs.mPassword),
78
0
     mNetNs(rhs.mNetNs),
79
0
     mPath(rhs.mPath),
80
0
     mHostCanonicalized(rhs.mHostCanonicalized),
81
0
     mCanonicalHost(rhs.mCanonicalHost),
82
0
     mIsBetweenAngleQuotes(rhs.mIsBetweenAngleQuotes),
83
0
     mEmbeddedHeadersText(rhs.mEmbeddedHeadersText.get() ? new Data(*rhs.mEmbeddedHeadersText) : 0),
84
0
     mEmbeddedHeaders(rhs.mEmbeddedHeaders.get() ? new SipMessage(*rhs.mEmbeddedHeaders) : 0)
85
0
{}
86
87
88
Uri::~Uri()
89
31.7k
{}
90
91
// RFC 3261 19.1.6
92
#if 0  // deprecated
93
Uri
94
Uri::fromTel(const Uri& tel, const Data& host)
95
{
96
   resip_assert(tel.scheme() == Symbols::Tel);
97
98
   Uri u;
99
   u.scheme() = Symbols::Sip;
100
   u.user() = tel.user();
101
   u.host() = host;
102
   u.param(p_user) = Symbols::Phone;
103
104
   // need to sort the user parameters
105
   if (!tel.userParameters().empty())
106
   {
107
      DebugLog(<< "Uri::fromTel: " << tel.userParameters());
108
      Data isub;
109
      Data postd;
110
111
      int totalSize  = 0;
112
      std::set<Data> userParameters;
113
114
      ParseBuffer pb(tel.userParameters().data(), tel.userParameters().size());
115
      while (true)
116
      {
117
         const char* anchor = pb.position();
118
         pb.skipToChar(Symbols::SEMI_COLON[0]);
119
         Data param = pb.data(anchor);
120
         // !dlb! not supposed to lowercase extension parameters
121
         param.lowercase();
122
         totalSize += param.size() + 1;
123
124
         if (param.prefix(Symbols::Isub))
125
         {
126
            isub = param;
127
         }
128
         else if (param.prefix(Symbols::Postd))
129
         {
130
            postd = param;
131
         }
132
         else
133
         {
134
            userParameters.insert(param);
135
         }
136
         if (pb.eof())
137
         {
138
            break;
139
         }
140
         else
141
         {
142
            pb.skipChar();
143
         }
144
      }
145
146
      u.userParameters().reserve(totalSize);
147
      if (!isub.empty())
148
      {
149
         u.userParameters() = isub;
150
      }
151
      if (!postd.empty())
152
      {
153
         if (!u.userParameters().empty())
154
         {
155
            u.userParameters() += Symbols::SEMI_COLON[0];
156
         }
157
         u.userParameters() += postd;
158
      }
159
      
160
      for(std::set<Data>::const_iterator i = userParameters.begin();
161
          i != userParameters.end(); ++i)
162
      {
163
         DebugLog(<< "Adding param: " << *i);
164
         if (!u.userParameters().empty())
165
         {
166
            u.userParameters() += Symbols::SEMI_COLON[0];
167
         }
168
         u.userParameters() += *i;
169
      }
170
   }
171
172
   return u;
173
}
174
#endif // deprecated
175
176
Uri
177
Uri::fromTel(const Uri& tel, const Uri& hostUri)
178
0
{
179
0
   resip_assert(tel.scheme() == Symbols::Tel);
180
181
0
   Uri u(hostUri);
182
0
   u.scheme() = Symbols::Sip;
183
0
   u.user() = tel.user();
184
0
   u.param(p_user) = Symbols::Phone;
185
186
   // need to sort the user parameters
187
0
   if (!tel.userParameters().empty())
188
0
   {
189
0
      DebugLog(<< "Uri::fromTel: " << tel.userParameters());
190
0
      Data isub;
191
0
      Data postd;
192
193
0
      int totalSize  = 0;
194
0
      std::set<Data> userParameters;
195
196
0
      ParseBuffer pb(tel.userParameters().data(), tel.userParameters().size());
197
0
      while (true)
198
0
      {
199
0
         const char* anchor = pb.position();
200
0
         pb.skipToChar(Symbols::SEMI_COLON[0]);
201
0
         Data param = pb.data(anchor);
202
         // !dlb! not supposed to lowercase extension parameters
203
0
         param.lowercase();
204
0
         totalSize += (int)param.size() + 1;
205
206
0
         if (param.prefix(Symbols::Isub))
207
0
         {
208
0
            isub = param;
209
0
         }
210
0
         else if (param.prefix(Symbols::Postd))
211
0
         {
212
0
            postd = param;
213
0
         }
214
0
         else
215
0
         {
216
0
            userParameters.insert(param);
217
0
         }
218
0
         if (pb.eof())
219
0
         {
220
0
            break;
221
0
         }
222
0
         else
223
0
         {
224
0
            pb.skipChar();
225
0
         }
226
0
      }
227
228
0
      u.userParameters().reserve(totalSize);
229
0
      if (!isub.empty())
230
0
      {
231
0
         u.userParameters() = isub;
232
0
      }
233
0
      if (!postd.empty())
234
0
      {
235
0
         if (!u.userParameters().empty())
236
0
         {
237
0
            u.userParameters() += Symbols::SEMI_COLON[0];
238
0
         }
239
0
         u.userParameters() += postd;
240
0
      }
241
      
242
0
      for(std::set<Data>::const_iterator i = userParameters.begin();
243
0
          i != userParameters.end(); ++i)
244
0
      {
245
0
         DebugLog(<< "Adding param: " << *i);
246
0
         if (!u.userParameters().empty())
247
0
         {
248
0
            u.userParameters() += Symbols::SEMI_COLON[0];
249
0
         }
250
0
         u.userParameters() += *i;
251
0
      }
252
0
   }
253
254
0
   return u;
255
0
}
256
257
bool
258
Uri::isEnumSearchable() const
259
0
{
260
0
   checkParsed();
261
0
   int digits = 0;
262
263
0
   if(mScheme != Symbols::Tel)
264
0
   {
265
0
      StackLog(<< "not a tel Uri");
266
0
      return false;
267
0
   }
268
269
0
   if(mUser.size() < 4)
270
0
   {
271
0
      StackLog(<< "user part of Uri empty or too short for E.164");
272
0
      return false;
273
0
   }
274
275
   // E.164 numbers must begin with a + and have at least
276
   // 3 digits
277
0
   if(mUser[0] != '+')
278
0
   {
279
0
      StackLog(<< "user part of Uri does not begin with `+' or too short");
280
0
      return false;
281
0
   }
282
283
   // count the digits (skip the leading `+')
284
0
   for(const char* i=user().begin() + 1; i!= user().end(); i++)
285
0
   {
286
0
      if (isdigit(static_cast< unsigned char >(*i)))
287
0
      {
288
0
         digits++;
289
0
      }
290
0
      else
291
0
      {
292
0
         if (*i != '-')
293
0
         {
294
0
            StackLog(<< "user part of Uri contains non-digit: " << *i);
295
0
            return false; // Only digits and '-' permitted
296
0
         }
297
0
      }
298
0
   }
299
0
   if(digits > 15)
300
0
   {
301
      // E.164 only permits 15 digits in a phone number
302
0
      StackLog(<< "user part of Uri contains more than 15 digits");
303
0
      return false;
304
0
   }
305
306
0
   DebugLog(<< "is in E.164 format for ENUM: " << mUser);
307
0
   return true;
308
0
}
309
310
std::vector<Data> 
311
Uri::getEnumLookups(const std::vector<Data>& suffixes) const
312
0
{
313
0
   std::vector<Data> results;
314
0
   Data prefix;
315
0
   if (isEnumSearchable())
316
0
   {
317
      // skip the leading +
318
0
      for (const char* i=user().end()-1 ; i!= user().begin(); --i)
319
0
      {
320
0
         if (isdigit(static_cast< unsigned char >(*i)))
321
0
         {
322
0
            prefix += *i;
323
0
            prefix += Symbols::DOT;
324
0
         }
325
0
      }
326
0
      StackLog(<< "E.164 number reversed for ENUM query: " << prefix);
327
0
      for (std::vector<Data>::const_iterator j=suffixes.begin(); j != suffixes.end(); ++j)
328
0
      {
329
0
         results.push_back(prefix + *j);
330
0
      }
331
0
   }
332
0
   return results;
333
0
}
334
335
bool
336
Uri::hasEmbedded() const
337
0
{
338
0
   checkParsed(); 
339
0
   return (mEmbeddedHeadersText.get() && !mEmbeddedHeadersText->empty()) || mEmbeddedHeaders.get() != 0;
340
0
}
341
342
void 
343
Uri::removeEmbedded()
344
0
{
345
0
   checkParsed();
346
0
   mEmbeddedHeaders.reset();
347
0
   mEmbeddedHeadersText.reset();
348
0
}
349
350
Uri&
351
Uri::operator=(const Uri& rhs)
352
2.89k
{
353
2.89k
   if (this != &rhs)
354
2.89k
   {
355
2.89k
      ParserCategory::operator=(rhs);
356
2.89k
      mScheme = rhs.mScheme;
357
2.89k
      mHost = rhs.mHost;
358
2.89k
      mPath = rhs.mPath;
359
2.89k
      mHostCanonicalized = rhs.mHostCanonicalized;
360
2.89k
      mCanonicalHost = rhs.mCanonicalHost;
361
2.89k
      mUser = rhs.mUser;
362
2.89k
      mUserParameters = rhs.mUserParameters;
363
2.89k
      mPort = rhs.mPort;
364
2.89k
      mPassword = rhs.mPassword;
365
2.89k
      mNetNs = rhs.mNetNs;
366
2.89k
      if (rhs.mEmbeddedHeaders.get() != 0)
367
0
      {
368
0
         mEmbeddedHeaders.reset(new SipMessage(*rhs.mEmbeddedHeaders));
369
0
      }
370
2.89k
      else if(rhs.mEmbeddedHeadersText.get() != 0)
371
1.07k
      {
372
1.07k
         if(!mEmbeddedHeadersText.get())
373
1.07k
         {
374
1.07k
            mEmbeddedHeadersText.reset(new Data(*rhs.mEmbeddedHeadersText));
375
1.07k
         }
376
0
         else
377
0
         {
378
            // !bwc! Data::operator= is smart enough to handle this safely.
379
0
            *mEmbeddedHeadersText = *rhs.mEmbeddedHeadersText;
380
0
         }
381
1.07k
      }
382
2.89k
   }
383
2.89k
   return *this;
384
2.89k
}
385
386
/**
387
  @class OrderUnknownParameters
388
  @brief used as a comparator for sorting purposes
389
  */
390
class OrderUnknownParameters
391
{
392
   public:
393
      /**
394
        @brief constructor ; never called explicitly
395
        */
396
0
      OrderUnknownParameters() { notUsed=false; };
397
398
      /**
399
        @brief empty destructor
400
        */
401
0
      ~OrderUnknownParameters() {};
402
403
      /**
404
        @brief used as a comparator for sorting purposes
405
         This does a straight Data comparison for name and returns true/false
406
        @param p1 pointer to parameter 1
407
        @param p2 pointer to parameter 2
408
        @return true if p1->getName() is less than p2->getName() 
409
         else return false
410
        */
411
      bool operator()(const Parameter* p1, const Parameter* p2) const
412
0
      {
413
0
         return dynamic_cast<const UnknownParameter*>(p1)->getName() < dynamic_cast<const UnknownParameter*>(p2)->getName();
414
0
      }
415
416
   private:
417
      bool notUsed;
418
};
419
420
bool Uri::compareUriParametersEqual(Parameter* param1, Parameter* param2)
421
0
{
422
0
   if (!param1 || !param2)
423
0
   {
424
0
      return false;
425
0
   }
426
427
0
   switch (param1->getType()) {
428
0
      case ParameterTypes::user:
429
0
      case ParameterTypes::method:
430
0
      case ParameterTypes::maddr:
431
0
      case ParameterTypes::transport:
432
0
      case ParameterTypes::rinstance:
433
0
      case ParameterTypes::comp:
434
0
      case ParameterTypes::extension:
435
0
      case ParameterTypes::wsSrcIp:
436
0
      case ParameterTypes::sigcompId:
437
0
         return isEqualNoCase(dynamic_cast<DataParameter*>(param1)->value(),
438
0
                              dynamic_cast<DataParameter*>(param2)->value());
439
440
0
      case ParameterTypes::ttl:
441
0
      case ParameterTypes::duration:
442
0
      case ParameterTypes::wsSrcPort:
443
0
         return dynamic_cast<UInt32Parameter*>(param1)->value() ==
444
0
                dynamic_cast<UInt32Parameter*>(param2)->value();
445
446
0
      case ParameterTypes::gr:
447
0
         return isEqualNoCase(dynamic_cast<ExistsOrDataParameter*>(param1)->value(),
448
0
                              dynamic_cast<ExistsOrDataParameter*>(param2)->value());
449
450
0
      case ParameterTypes::lr:
451
0
      case ParameterTypes::ob:
452
         // Exists parameters are equal.
453
0
         return true;
454
455
0
      default:
456
         // Other parameters are not considered.
457
         // Parameters may be added accordingly to RFCs.
458
0
         return true;
459
0
   }
460
0
}
461
462
bool Uri::compareUriParametersLessThan(Parameter* param1, Parameter* param2)
463
0
{
464
0
   if (!param1 || !param2)
465
0
   {
466
0
      return false;
467
0
   }
468
469
0
   switch (param1->getType()) {
470
0
      case ParameterTypes::user:
471
0
      case ParameterTypes::method:
472
0
      case ParameterTypes::maddr:
473
0
      case ParameterTypes::transport:
474
0
      case ParameterTypes::rinstance:
475
0
      case ParameterTypes::comp:
476
0
      case ParameterTypes::extension:
477
0
      case ParameterTypes::wsSrcIp:
478
0
      case ParameterTypes::sigcompId:
479
0
         return isLessThanNoCase(dynamic_cast<DataParameter*>(param1)->value(),
480
0
                                 dynamic_cast<DataParameter*>(param2)->value());
481
482
0
      case ParameterTypes::ttl:
483
0
      case ParameterTypes::duration:
484
0
      case ParameterTypes::wsSrcPort:
485
0
         return dynamic_cast<UInt32Parameter*>(param1)->value() <
486
0
                dynamic_cast<UInt32Parameter*>(param2)->value();
487
488
0
      case ParameterTypes::gr:
489
0
         return isLessThanNoCase(dynamic_cast<ExistsOrDataParameter*>(param1)->value(),
490
0
                                 dynamic_cast<ExistsOrDataParameter*>(param2)->value());
491
492
0
      case ParameterTypes::lr:
493
0
      case ParameterTypes::ob:
494
         // Exists parameters are equal.
495
0
         return false;
496
497
0
      default:
498
         // Other parameters are not considered.
499
         // Parameters may be added accordingly to RFCs.
500
0
         return false;
501
0
   }
502
0
}
503
504
bool Uri::isSignificantUriParameter(const ParameterTypes::Type type) noexcept
505
0
{
506
0
   return type == ParameterTypes::user ||
507
0
          type == ParameterTypes::ttl ||
508
0
          type == ParameterTypes::method ||
509
0
          type == ParameterTypes::maddr ||
510
0
          type == ParameterTypes::transport;
511
0
}
512
513
bool 
514
Uri::operator==(const Uri& other) const
515
0
{
516
0
   checkParsed();
517
0
   other.checkParsed();
518
519
   // compare hosts
520
0
   if (DnsUtil::isIpV6Address(mHost) &&
521
0
       DnsUtil::isIpV6Address(other.mHost))
522
0
   {
523
      // compare canonicalized IPV6 addresses
524
525
      // update canonicalized if host changed
526
0
      if (!mHostCanonicalized)
527
0
      {
528
0
         mCanonicalHost = DnsUtil::canonicalizeIpV6Address(mHost);
529
0
         mHostCanonicalized=true;
530
0
      }
531
532
      // update canonicalized if host changed
533
0
      if (!other.mHostCanonicalized)
534
0
      {
535
0
         other.mCanonicalHost = DnsUtil::canonicalizeIpV6Address(other.mHost);
536
0
         other.mHostCanonicalized=true;
537
0
      }
538
539
0
      if (mCanonicalHost != other.mCanonicalHost)
540
0
      {
541
0
         return false;
542
0
      }
543
0
   }
544
0
   else
545
0
   {
546
0
      if (!isEqualNoCase(mHost, other.mHost))
547
0
      {
548
0
         return false;
549
0
      }
550
0
   }
551
   
552
0
   if (isEqualNoCase(mScheme, other.mScheme) &&
553
0
       ((isEqualNoCase(mScheme, Symbols::Sip) || isEqualNoCase(mScheme, Symbols::Sips)) ? mUser == other.mUser : isEqualNoCase(mUser, other.mUser)) &&
554
0
       isEqualNoCase(mUserParameters,other.mUserParameters) &&
555
0
       mPassword == other.mPassword &&
556
0
       mPort == other.mPort &&
557
0
       mNetNs == other.mNetNs &&
558
0
       mPath == mPath)
559
0
   {
560
0
      for (ParameterList::const_iterator it = mParameters.begin(); it != mParameters.end(); ++it)
561
0
      {
562
0
         Parameter* otherParam = other.getParameterByEnum((*it)->getType());
563
564
0
         if (Uri::isSignificantUriParameter((*it)->getType()) || otherParam)
565
0
         {
566
0
            if (!Uri::compareUriParametersEqual(*it, otherParam))
567
0
            {
568
0
               return false;
569
0
            }
570
0
         }
571
0
      }         
572
573
      // now check the other way, sigh
574
0
      for (ParameterList::const_iterator it = other.mParameters.begin(); it != other.mParameters.end(); ++it)
575
0
      {
576
0
         Parameter* param = getParameterByEnum((*it)->getType());
577
578
0
         if (Uri::isSignificantUriParameter((*it)->getType()) || param)
579
0
         {
580
0
            if (!Uri::compareUriParametersEqual(*it, param))
581
0
            {
582
0
               return false;
583
0
            }
584
0
         }
585
0
      }
586
0
   }
587
0
   else
588
0
   {
589
0
      return false;
590
0
   }
591
592
0
   OrderUnknownParameters orderUnknown;
593
594
#if defined(__SUNPRO_CC) || defined(WIN32) || defined(__sun__)
595
   // The Solaris Forte STL implementation does not support the
596
   // notion of a list.sort() function taking a BinaryPredicate.
597
   // The hacky workaround is to load the Parameter pointers into
598
   // an STL set which does support an ordering function.
599
600
   typedef std::set<Parameter*, OrderUnknownParameters> ParameterSet;
601
   ParameterSet unA, unB;
602
603
   for (ParameterList::const_iterator i = mUnknownParameters.begin();
604
        i != mUnknownParameters.end(); ++i)
605
   {
606
      unA.insert(*i);
607
   }
608
   for (ParameterList::const_iterator i = other.mUnknownParameters.begin();
609
        i != other.mUnknownParameters.end(); ++i)
610
   {
611
      unB.insert(*i);
612
   }
613
614
   ParameterSet::iterator a = unA.begin();
615
   ParameterSet::iterator b = unB.begin();
616
#else
617
   // .dlb. more efficient to copy to vector for sorting?
618
   // Uri comparison is expensive; consider caching? ugh
619
0
   ParameterList unA = mUnknownParameters;
620
0
   ParameterList unB = other.mUnknownParameters;
621
622
0
   sort(unA.begin(), unA.end(), orderUnknown);
623
0
   sort(unB.begin(), unB.end(), orderUnknown);
624
 
625
0
   ParameterList::iterator a = unA.begin();
626
0
   ParameterList::iterator b = unB.begin();
627
0
#endif
628
629
0
   while(a != unA.end() && b != unB.end())
630
0
   {
631
0
      if (orderUnknown(*a, *b))
632
0
      {
633
0
         ++a;
634
0
      }
635
0
      else if (orderUnknown(*b, *a))
636
0
      {
637
0
         ++b;
638
0
      }
639
0
      else
640
0
      {
641
0
         if (!isEqualNoCase(dynamic_cast<UnknownParameter*>(*a)->value(),
642
0
                            dynamic_cast<UnknownParameter*>(*b)->value()))
643
0
         {
644
0
            return false;
645
0
         }
646
0
         ++a;
647
0
         ++b;
648
0
      }
649
0
   }
650
0
   return true;
651
0
}
652
653
bool 
654
Uri::operator!=(const Uri& other) const
655
0
{
656
0
   return !(*this == other);
657
0
}
658
659
bool
660
Uri::operator<(const Uri& other) const
661
0
{
662
0
   other.checkParsed();
663
0
   checkParsed();
664
0
   if (mUser < other.mUser)
665
0
   {
666
0
      return true;
667
0
   }
668
669
0
   if (mUser > other.mUser)
670
0
   {
671
0
      return false;
672
0
   }
673
674
0
   if (mUserParameters < other.mUserParameters)
675
0
   {
676
0
      return true;
677
0
   }
678
679
0
   if (mUserParameters > other.mUserParameters)
680
0
   {
681
0
      return false;
682
0
   }
683
684
   // !bwc! Canonicalize before we compare! Jeez...
685
0
   if (!mHostCanonicalized)
686
0
   {
687
0
      if(DnsUtil::isIpV6Address(mHost))
688
0
      {
689
0
         mCanonicalHost = DnsUtil::canonicalizeIpV6Address(mHost);
690
0
      }
691
0
      else
692
0
      {
693
0
         mCanonicalHost = mHost;
694
0
         mCanonicalHost.lowercase();
695
0
      }
696
0
      mHostCanonicalized=true;
697
0
   }
698
   
699
0
   if (!other.mHostCanonicalized)
700
0
   {
701
0
      if(DnsUtil::isIpV6Address(other.mHost))
702
0
      {
703
0
         other.mCanonicalHost = DnsUtil::canonicalizeIpV6Address(other.mHost);
704
0
      }
705
0
      else
706
0
      {
707
0
         other.mCanonicalHost = other.mHost;
708
0
         other.mCanonicalHost.lowercase();
709
0
      }
710
0
      other.mHostCanonicalized=true;
711
0
   }
712
713
0
   if (mCanonicalHost < other.mCanonicalHost)
714
0
   {
715
0
      return true;
716
0
   }
717
718
0
   if (mCanonicalHost > other.mCanonicalHost)
719
0
   {
720
0
      return false;
721
0
   }
722
723
0
   if (mPort < other.mPort)
724
0
   {
725
0
      return true;
726
0
   }
727
728
0
   if (mPort > other.mPort)
729
0
   {
730
0
      return false;
731
0
   }
732
733
0
   for (ParameterList::const_iterator it = mParameters.begin(); it != mParameters.end(); ++it)
734
0
      {
735
0
         Parameter* otherParam = other.getParameterByEnum((*it)->getType());
736
737
0
         if (otherParam)
738
0
         {
739
0
            if (Uri::compareUriParametersLessThan(*it, otherParam)) {
740
0
               return true;
741
0
            }
742
743
0
            if (Uri::compareUriParametersLessThan(otherParam, *it)) {
744
0
               return false;
745
0
            }
746
0
         }
747
0
         else if (Uri::isSignificantUriParameter((*it)->getType()))
748
0
         {
749
0
            return true;  // Significant URI params should not be ignored.
750
0
         }
751
0
      }
752
753
   // Sort unknown parameters from both URIs by their name using comparator class.
754
0
   OrderUnknownParameters orderUnknown;
755
756
#if defined(__SUNPRO_CC) || defined(WIN32) || defined(__sun__)
757
   // The Solaris Forte STL implementation does not support the
758
   // notion of a list.sort() function taking a BinaryPredicate.
759
   // The hacky workaround is to load the Parameter pointers into
760
   // an STL set which does support an ordering function.
761
762
   typedef std::set<Parameter*, OrderUnknownParameters> ParameterSet;
763
   ParameterSet thisUriParamList, otherUriParamList;
764
765
   for (ParameterList::const_iterator i = mUnknownParameters.begin();
766
        i != mUnknownParameters.end(); ++i)
767
   {
768
      thisUriParamList.insert(*i);
769
   }
770
   for (ParameterList::const_iterator i = other.mUnknownParameters.begin();
771
        i != other.mUnknownParameters.end(); ++i)
772
   {
773
      otherUriParamList.insert(*i);
774
   }
775
#else
776
0
   ParameterList thisUriParamList = mUnknownParameters;
777
0
   ParameterList otherUriParamList = other.mUnknownParameters;
778
779
0
   sort(thisUriParamList.begin(), thisUriParamList.end(), orderUnknown);
780
0
   sort(otherUriParamList.begin(), otherUriParamList.end(), orderUnknown);
781
0
#endif
782
783
0
   auto thisUriParam = thisUriParamList.begin();
784
0
   auto otherUriParam = otherUriParamList.begin();
785
786
   // Iterate through unknown parameters of both URIs.
787
   // Advance iterators to compare values of parameters with matching names.
788
0
   while(thisUriParam != thisUriParamList.end() && otherUriParam != otherUriParamList.end())
789
0
   {
790
0
      if (orderUnknown(*thisUriParam, *otherUriParam))
791
0
      {
792
         // this < other param name.
793
0
         ++thisUriParam;
794
0
      }
795
0
      else if (orderUnknown(*otherUriParam, *thisUriParam))
796
0
      {
797
         // other < this param name.
798
0
         ++otherUriParam;
799
0
      }
800
0
      else
801
0
      {
802
         // this == other param name.
803
         // Unknown parameter names are the same. Compare their values.
804
0
         const Data& thisParamValue = dynamic_cast<UnknownParameter*>(*thisUriParam)->value();
805
0
         const Data& otherParamValue = dynamic_cast<UnknownParameter*>(*otherUriParam)->value();
806
807
0
         if (isLessThanNoCase(thisParamValue,
808
0
                              otherParamValue))
809
0
         {
810
0
            return true;
811
0
         }
812
813
0
         if (isLessThanNoCase(otherParamValue,
814
0
                              thisParamValue))
815
0
         {
816
0
            return false;
817
0
         }
818
819
         // Move iterators to the next position.
820
0
         ++thisUriParam;
821
0
         ++otherUriParam;
822
0
      }
823
0
   }
824
825
0
   return false;
826
0
}
827
828
bool
829
Uri::aorEqual(const resip::Uri& rhs) const
830
0
{
831
0
   checkParsed();
832
0
   rhs.checkParsed();
833
834
0
   if (!mHostCanonicalized)
835
0
   {
836
0
      if(DnsUtil::isIpV6Address(mHost))
837
0
      {
838
0
         mCanonicalHost = DnsUtil::canonicalizeIpV6Address(mHost);
839
0
      }
840
0
      else
841
0
      {
842
0
         mCanonicalHost = mHost;
843
0
         mCanonicalHost.lowercase();
844
0
      }
845
0
      mHostCanonicalized=true;
846
0
   }
847
   
848
0
   if (!rhs.mHostCanonicalized)
849
0
   {
850
0
      if(DnsUtil::isIpV6Address(rhs.mHost))
851
0
      {
852
0
         rhs.mCanonicalHost = DnsUtil::canonicalizeIpV6Address(rhs.mHost);
853
0
      }
854
0
      else
855
0
      {
856
0
         rhs.mCanonicalHost = rhs.mHost;
857
0
         rhs.mCanonicalHost.lowercase();
858
0
      }
859
0
      rhs.mHostCanonicalized=true;
860
0
   }
861
   
862
0
   return (mUser == rhs.mUser) && (mCanonicalHost == rhs.mCanonicalHost) && (mPort == rhs.mPort) &&
863
0
           isEqualNoCase(mScheme, rhs.mScheme) && (mNetNs == rhs.mNetNs);
864
0
}
865
866
void 
867
Uri::getAorInternal(bool dropScheme, bool addPort, Data& aor) const
868
0
{
869
0
   checkParsed();
870
   // canonicalize host
871
872
0
   addPort = addPort && mPort!=0;
873
874
0
   bool hostIsIpV6Address = DnsUtil::isIpV6Address(mHost);
875
0
   if(!mHostCanonicalized)
876
0
   {
877
0
      if (hostIsIpV6Address)
878
0
      {
879
0
         mCanonicalHost = DnsUtil::canonicalizeIpV6Address(mHost);
880
0
      }
881
0
      else
882
0
      {
883
0
         mCanonicalHost = mHost;
884
0
         mCanonicalHost.lowercase();
885
0
      }
886
0
      mHostCanonicalized = true;
887
0
   }
888
889
   // !bwc! Maybe reintroduce caching of aor. (Would use a bool instead of the
890
   // mOldX cruft)
891
   //                                                  @:10000
892
0
   aor.clear();
893
0
   aor.reserve((dropScheme ? 0 : mScheme.size()+1)
894
0
       + mUser.size() + mCanonicalHost.size() + 7);
895
0
   if(!dropScheme)
896
0
   {
897
0
      aor += mScheme;
898
0
      aor += ':';
899
0
   }
900
901
0
   if (!mUser.empty())
902
0
   {
903
0
#ifdef HANDLE_CHARACTER_ESCAPING
904
0
      {
905
0
         oDataStream str(aor);
906
0
         mUser.escapeToStream(str, getUserEncodingTable()); 
907
0
      }
908
#else
909
      aor += mUser;
910
#endif
911
0
      if(!mCanonicalHost.empty())
912
0
      {
913
0
         aor += Symbols::AT_SIGN;
914
0
      }
915
0
   }
916
917
0
   if(hostIsIpV6Address && addPort)
918
0
   {
919
0
      aor += Symbols::LS_BRACKET;
920
0
      aor += mCanonicalHost;
921
0
      aor += Symbols::RS_BRACKET;
922
0
   }
923
0
   else
924
0
   {
925
0
      aor += mCanonicalHost;
926
0
   }
927
928
0
   if(addPort)
929
0
   {
930
0
      aor += Symbols::COLON;
931
0
      aor += Data(mPort);
932
0
   }
933
0
}
934
935
Data 
936
Uri::getAOR(bool addPort) const
937
0
{
938
0
   Data result;
939
0
   getAorInternal(false, addPort, result);
940
0
   return result;
941
0
}
942
943
bool 
944
Uri::userIsTelephoneSubscriber() const
945
0
{
946
0
   try
947
0
   {
948
0
      ParseBuffer pb(mUser);
949
0
      pb.assertNotEof();
950
0
      const char* anchor=pb.position();
951
0
      bool local=false;
952
0
      if(*pb.position()=='+')
953
0
      {
954
         // Might be a global phone number
955
0
         pb.skipChar();
956
0
         pb.skipChars(getGlobalNumberTable());
957
0
      }
958
0
      else
959
0
      {
960
0
         pb.skipChars(getLocalNumberTable());
961
0
         local=true;
962
0
      }
963
964
0
      Data dialString(pb.data(anchor));
965
0
      if(dialString.empty())
966
0
      {
967
0
         pb.fail(__FILE__, __LINE__, "Dial string is empty.");
968
0
      }
969
970
      // ?bwc? More dial-string checking? For instance, +/ (or simply /) is not 
971
      // a valid dial-string according to the BNF; the string must contain at 
972
      // least one actual digit (or in the local number case, one hex digit or 
973
      // '*' or '#'. Interestingly, this means that stuff like ///*/// is 
974
      // valid)
975
976
      // Dial string looks ok so far; now look for params (there must be a 
977
      // phone-context param if this is a local number, otherwise there might 
978
      // or might not be one)
979
0
      if(local || !pb.eof())
980
0
      {
981
         // The only thing that can be here is a ';'. If it does, we're going 
982
         // to say it is good enough for us. If something in the parameter 
983
         // string is malformed, it'll get caught when/if 
984
         // getUserAsTelephoneSubscriber() is called.
985
0
         pb.skipChar(';');
986
0
      }
987
988
0
      return true;
989
0
   }
990
0
   catch(ParseException& /*e*/)
991
0
   {
992
0
      return false;
993
0
   }
994
0
}
995
996
Token 
997
Uri::getUserAsTelephoneSubscriber() const
998
0
{
999
   // !bwc! Ugly. Someday, refactor all this lazy-parser stuff and make it 
1000
   // possible to control ownership explicitly.
1001
   // Set this up as lazy-parsed, to prevent exceptions from being thrown.
1002
0
   HeaderFieldValue temp(mUser.data(), mUser.size());
1003
0
   Token tempToken(temp, Headers::NONE);
1004
   // tempToken does not own the HeaderFieldValue temp, and temp does not own 
1005
   // its buffer.
1006
1007
   // Here's the voodoo; invoking operator= makes a deep copy of the stuff in
1008
   // tempToken, with result owning the memory, and result is in the unparsed 
1009
   // state.
1010
0
   Token result = tempToken;
1011
0
   return result;
1012
0
}
1013
1014
void 
1015
Uri::setUserAsTelephoneSubscriber(const Token& telephoneSubscriber)
1016
0
{
1017
0
   mUser.clear();
1018
0
   oDataStream str(mUser);
1019
0
   str << telephoneSubscriber;
1020
0
}
1021
1022
Data
1023
Uri::getAorNoPort() const
1024
0
{
1025
0
   Data result;
1026
0
   getAorInternal(true, false, result);
1027
0
   return result;
1028
0
}
1029
1030
Data
1031
Uri::getAor() const
1032
0
{
1033
0
   Data result;
1034
0
   getAorInternal(true, true, result);
1035
0
   return result;
1036
0
}
1037
1038
Uri 
1039
Uri::getAorAsUri(TransportType transportTypeToRemoveDefaultPort) const
1040
0
{   
1041
   //.dcm. -- tel conversion?
1042
0
   checkParsed();
1043
0
   Uri ret;
1044
0
   ret.scheme() = mScheme;   
1045
0
   ret.user() = mUser;
1046
0
   ret.host() = mHost;
1047
1048
   // Remove any default ports (if required)
1049
0
   if(transportTypeToRemoveDefaultPort == UDP || 
1050
0
       transportTypeToRemoveDefaultPort == TCP)
1051
0
   {
1052
0
      if(mPort != Symbols::DefaultSipPort)
1053
0
      {
1054
0
         ret.port() = mPort;
1055
0
      }
1056
0
   }
1057
0
   else if (transportTypeToRemoveDefaultPort == TLS || 
1058
0
            transportTypeToRemoveDefaultPort == DTLS)
1059
0
   {
1060
0
      if(mPort != Symbols::DefaultSipsPort)
1061
0
      {
1062
0
         ret.port() = mPort;
1063
0
      }
1064
0
   }
1065
0
   else
1066
0
   {
1067
0
      ret.port() = mPort;
1068
0
   }
1069
1070
0
   return ret;
1071
0
}
1072
1073
void
1074
Uri::parse(ParseBuffer& pb)
1075
18.4k
{
1076
18.4k
   pb.skipWhitespace();
1077
18.4k
   const char* start = pb.position();
1078
1079
   // Relative URLs (typically HTTP) start with a slash.  These
1080
   // are seen when parsing the WebSocket handshake.
1081
18.4k
   if (*pb.position() == Symbols::SLASH[0])
1082
783
   {
1083
783
      mScheme.clear();
1084
783
      pb.skipToOneOf("?;", ParseBuffer::Whitespace);
1085
783
      pb.data(mPath, start);
1086
783
      if (!pb.eof() && !ParseBuffer::oneOf(*pb.position(), ParseBuffer::Whitespace))
1087
618
      {
1088
618
         parseParameters(pb);
1089
618
      }
1090
783
      return;
1091
783
   }
1092
1093
17.6k
   pb.skipToOneOf(":@");
1094
1095
17.6k
   pb.assertNotEof();
1096
1097
17.6k
   pb.data(mScheme, start);
1098
17.6k
   pb.skipChar(Symbols::COLON[0]);
1099
17.6k
   mScheme.schemeLowercase();
1100
1101
17.6k
   if (mScheme==Symbols::Tel)
1102
45
   {
1103
45
      const char* anchor = pb.position();
1104
45
      static std::bitset<256> delimiter=Data::toBitset("\r\n\t ;>");
1105
45
      pb.skipToOneOf(delimiter);
1106
45
      pb.data(mUser, anchor);
1107
45
      if (!pb.eof() && *pb.position() == Symbols::SEMI_COLON[0])
1108
11
      {
1109
11
         anchor = pb.skipChar();
1110
11
         pb.skipToOneOf(ParseBuffer::Whitespace, Symbols::RA_QUOTE);
1111
11
         pb.data(mUserParameters, anchor);
1112
11
      }
1113
45
      return;
1114
45
   }
1115
   
1116
17.5k
   start = pb.position();
1117
17.5k
   static std::bitset<256> userPortOrPasswordDelim(Data::toBitset("@:\""));
1118
   // stop at double-quote to prevent matching an '@' in a quoted string param. 
1119
17.5k
   pb.skipToOneOf(userPortOrPasswordDelim);
1120
17.5k
   if (!pb.eof())
1121
3.44k
   {
1122
3.44k
      const char* atSign=0;
1123
3.44k
      if (*pb.position() == Symbols::COLON[0])
1124
2.57k
      {
1125
         // Either a password, or a port
1126
2.57k
         const char* afterColon = pb.skipChar();
1127
2.57k
         pb.skipToOneOf("@\"");
1128
2.57k
         if(!pb.eof() && *pb.position() == Symbols::AT_SIGN[0])
1129
219
         {
1130
219
            atSign=pb.position();
1131
            // password
1132
219
#ifdef HANDLE_CHARACTER_ESCAPING
1133
219
            pb.dataUnescaped(mPassword, afterColon);
1134
#else
1135
            pb.data(mPassword, afterColon);
1136
#endif
1137
219
            pb.reset(afterColon-1);
1138
219
         }
1139
2.35k
         else
1140
2.35k
         {
1141
            // port. No user part.
1142
2.35k
            pb.reset(start);
1143
2.35k
         }
1144
2.57k
      }
1145
872
      else if(*pb.position() == Symbols::AT_SIGN[0])
1146
433
      {
1147
433
         atSign=pb.position();
1148
433
      }
1149
439
      else
1150
439
      {
1151
         // Only a hostpart
1152
439
         pb.reset(start);
1153
439
      }
1154
1155
3.44k
      if(atSign)
1156
593
      {
1157
593
#ifdef HANDLE_CHARACTER_ESCAPING
1158
593
         pb.dataUnescaped(mUser, start);
1159
#else
1160
         pb.data(mUser, start);
1161
#endif
1162
593
         pb.reset(atSign);
1163
593
         start = pb.skipChar();
1164
593
      }
1165
3.44k
   }
1166
14.1k
   else
1167
14.1k
   {
1168
14.1k
      pb.reset(start);
1169
14.1k
   }
1170
1171
17.5k
   if (pb.eof())
1172
432
   {
1173
432
      return;
1174
432
   }
1175
1176
17.1k
   mHostCanonicalized=false;
1177
17.1k
   static std::bitset<256> hostDelimiter(Data::toBitset("\r\n\t :;?>"));
1178
17.1k
   if (*start == '[')
1179
160
   {
1180
160
      start = pb.skipChar();
1181
160
      pb.skipToChar(']');
1182
160
      pb.data(mHost, start);
1183
160
      mCanonicalHost = DnsUtil::canonicalizeIpV6Address(mHost);
1184
160
      if (mCanonicalHost.empty())
1185
57
      {
1186
         // .bwc. So the V6 addy is garbage.
1187
57
         throw ParseException("Unparsable V6 address (note, this might"
1188
57
                                    " be unparsable because IPV6 support is not"
1189
57
                                    " enabled)","Uri",__FILE__,
1190
57
                                       __LINE__);
1191
57
      }
1192
103
      mHostCanonicalized = true;
1193
103
      pb.skipChar();
1194
103
      pb.skipToOneOf(hostDelimiter);
1195
103
   }
1196
16.9k
   else
1197
16.9k
   {
1198
16.9k
      pb.skipToOneOf(hostDelimiter);
1199
16.9k
      pb.data(mHost, start);
1200
16.9k
   }
1201
1202
17.0k
   if (!pb.eof() && *pb.position() == ':')
1203
375
   {
1204
375
      start = pb.skipChar();
1205
375
      mPort = pb.uInt32();
1206
375
   }
1207
16.7k
   else
1208
16.7k
   {
1209
16.7k
      mPort = 0;
1210
16.7k
   }
1211
1212
17.0k
   parseParameters(pb);
1213
1214
17.0k
   if (!pb.eof() && *pb.position() == Symbols::QUESTION[0])
1215
2.45k
   {
1216
2.45k
      const char* anchor = pb.position();
1217
1218
2.45k
      if (mIsBetweenAngleQuotes)
1219
37
      {
1220
         // Embedded headers will either end at the angle bracket (when Uri is in a NameAddr that uses angle 
1221
         // brackets) or at a semi-colon (when Uri is in a NameAddr that doesn't use angle brackets and has 
1222
         // NameAddr parameters following the embedded headers), or in Whitespace.
1223
         // We used to just look for either of the 3 terminators, however to be more tolerant of endpoints 
1224
         // that do not properly escape ;'s in the embedded headers, we relax the rules, only when the uri
1225
         // falls between angle quotes/brackets - in this case we will allow non-escaped semi-colons by only
1226
         // looking for > and whitespace as a terminator.
1227
37
         pb.skipToOneOf(">", ParseBuffer::Whitespace);
1228
37
      }
1229
2.42k
      else
1230
2.42k
      {
1231
2.42k
         pb.skipToOneOf(">;", ParseBuffer::Whitespace);
1232
2.42k
      }
1233
1234
2.45k
      if(!mEmbeddedHeadersText.get()) mEmbeddedHeadersText.reset(new Data);
1235
2.45k
      pb.data(*mEmbeddedHeadersText, anchor);
1236
2.45k
   }
1237
17.0k
}
1238
1239
ParserCategory*
1240
Uri::clone() const
1241
0
{
1242
0
   return new Uri(*this);
1243
0
}
1244
1245
ParserCategory*
1246
Uri::clone(void* location) const
1247
0
{
1248
0
   return new (location) Uri(*this);
1249
0
}
1250
1251
ParserCategory*
1252
Uri::clone(PoolBase* pool) const
1253
0
{
1254
0
   return new (pool) Uri(*this);
1255
0
}
1256
1257
void Uri::setUriUserEncoding(unsigned char c, bool encode) 
1258
0
{
1259
0
   getUserEncodingTable()[c] = encode; 
1260
0
}
1261
1262
void Uri::setUriPasswordEncoding(unsigned char c, bool encode)
1263
0
{
1264
0
   getPasswordEncodingTable()[c] = encode;
1265
0
}
1266
1267
// should not encode user parameters unless its a tel?
1268
EncodeStream& 
1269
Uri::encodeParsed(EncodeStream& str) const
1270
0
{
1271
   // Relative URIs may not have the scheme
1272
0
   if (!mScheme.empty())
1273
0
   {
1274
0
      str << mScheme << Symbols::COLON;
1275
0
   }
1276
1277
0
   if (!mUser.empty())
1278
0
   {
1279
0
#ifdef HANDLE_CHARACTER_ESCAPING
1280
0
      mUser.escapeToStream(str, getUserEncodingTable()); 
1281
#else
1282
      str << mUser;
1283
#endif
1284
0
      if (!mUserParameters.empty())
1285
0
      {
1286
0
         str << Symbols::SEMI_COLON[0] << mUserParameters;
1287
0
      }
1288
0
      if (!mPassword.empty())
1289
0
      {
1290
0
         str << Symbols::COLON;
1291
0
#ifdef HANDLE_CHARACTER_ESCAPING
1292
0
         mPassword.escapeToStream(str, getPasswordEncodingTable());
1293
#else
1294
         str << mPassword;
1295
#endif
1296
0
      }
1297
0
   }
1298
0
   if (!mHost.empty())
1299
0
   {
1300
0
     if (!mUser.empty())
1301
0
     {
1302
0
       str << Symbols::AT_SIGN;
1303
0
     }
1304
0
     if (DnsUtil::isIpV6Address(mHost))
1305
0
     {
1306
0
        str << '[' << mHost << ']';
1307
0
     }
1308
0
     else
1309
0
     {
1310
0
        str << mHost;
1311
0
     }
1312
0
   }
1313
0
   if (mPort != 0)
1314
0
   {
1315
0
      str << Symbols::COLON << mPort;
1316
0
   }
1317
0
   if (!mPath.empty())
1318
0
   {
1319
0
      str << mPath;
1320
0
   }
1321
0
   encodeParameters(str);
1322
0
   encodeEmbeddedHeaders(str);
1323
1324
0
   return str;
1325
0
}
1326
1327
SipMessage&
1328
Uri::embedded()
1329
6.23k
{
1330
6.23k
   checkParsed();
1331
6.23k
   if (mEmbeddedHeaders.get() == 0)
1332
3.19k
   {
1333
3.19k
      this->mEmbeddedHeaders.reset(new SipMessage());
1334
3.19k
      if (mEmbeddedHeadersText.get() && !mEmbeddedHeadersText->empty())
1335
1.21k
      {
1336
1.21k
         ParseBuffer pb(mEmbeddedHeadersText->data(), mEmbeddedHeadersText->size());
1337
1.21k
         this->parseEmbeddedHeaders(pb);
1338
1.21k
      }
1339
3.19k
   }
1340
1341
6.23k
   return *mEmbeddedHeaders;
1342
6.23k
}
1343
1344
const SipMessage&
1345
Uri::embedded() const
1346
0
{
1347
0
   Uri* ncthis = const_cast<Uri*>(this);
1348
0
   return ncthis->embedded();
1349
0
}
1350
1351
static const Data bodyData("Body");
1352
void
1353
Uri::parseEmbeddedHeaders(ParseBuffer& pb)
1354
1.21k
{
1355
1.21k
   DebugLog(<< "Uri::parseEmbeddedHeaders");
1356
1.21k
   if (!pb.eof() && *pb.position() == Symbols::QUESTION[0])
1357
1.21k
   {
1358
1.21k
      pb.skipChar();
1359
1.21k
   }
1360
1361
1.21k
   const char* anchor;
1362
1.21k
   Data headerName;
1363
1.21k
   Data headerContents;
1364
1365
1.21k
   bool first = true;
1366
961k
   while (!pb.eof())
1367
960k
   {
1368
960k
      if (first)
1369
1.17k
      {
1370
1.17k
         first = false;
1371
1.17k
      }
1372
959k
      else
1373
959k
      {
1374
959k
         pb.skipChar(Symbols::AMPERSAND[0]);
1375
959k
      }
1376
1377
960k
      anchor = pb.position();
1378
960k
      pb.skipToChar(Symbols::EQUALS[0]);
1379
960k
      pb.data(headerName, anchor);
1380
      // .dlb. in theory, need to decode header name
1381
1382
960k
      anchor = pb.skipChar(Symbols::EQUALS[0]);
1383
960k
      pb.skipToChar(Symbols::AMPERSAND[0]);
1384
960k
      pb.data(headerContents, anchor);
1385
1386
960k
      unsigned int len;
1387
960k
      char* decodedContents = Embedded::decode(headerContents, len);
1388
960k
      mEmbeddedHeaders->addBuffer(decodedContents);
1389
1390
960k
      if (isEqualNoCase(bodyData, headerName))
1391
13.2k
      {
1392
13.2k
         mEmbeddedHeaders->setBody(decodedContents, len); 
1393
13.2k
      }
1394
947k
      else
1395
947k
      {
1396
947k
         DebugLog(<< "Uri::parseEmbeddedHeaders(" << headerName << ", " << Data(decodedContents, len) << ")");
1397
947k
         mEmbeddedHeaders->addHeader(Headers::getType(headerName.data(), headerName.size()),
1398
947k
                                     headerName.data(), (int)headerName.size(),
1399
947k
                                     decodedContents, len);
1400
947k
      }
1401
960k
   }
1402
1.21k
}
1403
1404
EncodeStream& 
1405
Uri::encodeEmbeddedHeaders(EncodeStream& str) const
1406
0
{
1407
0
   if (mEmbeddedHeaders.get())
1408
0
   {
1409
0
      mEmbeddedHeaders->encodeEmbedded(str);
1410
0
   }
1411
0
   else if(mEmbeddedHeadersText.get())
1412
0
   {
1413
      // never decoded
1414
0
      str << *mEmbeddedHeadersText;
1415
0
   }
1416
0
   return str;
1417
0
}
1418
1419
Data 
1420
Uri::toString() const
1421
0
{
1422
0
   Data out;
1423
0
   {
1424
0
      oDataStream dataStream(out);
1425
0
      this->encodeParsed(dataStream);
1426
0
   }
1427
0
   return out;
1428
0
}
1429
1430
ParameterTypes::Factory Uri::ParameterFactories[ParameterTypes::MAX_PARAMETER]={0};
1431
1432
Parameter* 
1433
Uri::createParam(ParameterTypes::Type type, ParseBuffer& pb, const std::bitset<256>& terminators, PoolBase* pool)
1434
27.7k
{
1435
27.7k
   if(type > ParameterTypes::UNKNOWN && type < ParameterTypes::MAX_PARAMETER && ParameterFactories[type])
1436
18.6k
   {
1437
18.6k
      return ParameterFactories[type](type, pb, terminators, pool);
1438
18.6k
   }
1439
9.10k
   return 0;
1440
27.7k
}
1441
1442
bool 
1443
Uri::exists(const Param<Uri>& paramType) const
1444
0
{
1445
0
    checkParsed();
1446
0
    bool ret = getParameterByEnum(paramType.getTypeNum()) != NULL;
1447
0
    return ret;
1448
0
}
1449
1450
void 
1451
Uri::remove(const Param<Uri>& paramType)
1452
0
{
1453
0
    checkParsed();
1454
0
    removeParameterByEnum(paramType.getTypeNum());
1455
0
}
1456
1457
#define defineParam(_enum, _name, _type, _RFC_ref_ignored)                                                      \
1458
_enum##_Param::DType&                                                                                           \
1459
0
Uri::param(const _enum##_Param& paramType)                                                           \
1460
0
{                                                                                                               \
1461
0
   checkParsed();                                                                                               \
1462
0
   _enum##_Param::Type* p =                                                                                     \
1463
0
      static_cast<_enum##_Param::Type*>(getParameterByEnum(paramType.getTypeNum()));                            \
1464
0
   if (!p)                                                                                                      \
1465
0
   {                                                                                                            \
1466
0
      p = new _enum##_Param::Type(paramType.getTypeNum());                                                      \
1467
0
      mParameters.push_back(p);                                                                                 \
1468
0
   }                                                                                                            \
1469
0
   return p->value();                                                                                           \
1470
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&)
1471
                                                                                                                \
1472
const _enum##_Param::DType&                                                                                     \
1473
0
Uri::param(const _enum##_Param& paramType) const                                                     \
1474
0
{                                                                                                               \
1475
0
   checkParsed();                                                                                               \
1476
0
   _enum##_Param::Type* p =                                                                                     \
1477
0
      static_cast<_enum##_Param::Type*>(getParameterByEnum(paramType.getTypeNum()));                            \
1478
0
   if (!p)                                                                                                      \
1479
0
   {                                                                                                            \
1480
0
      InfoLog(<< "Missing parameter " _name " " << ParameterTypes::ParameterNames[paramType.getTypeNum()]);     \
1481
0
      DebugLog(<< *this);                                                                                       \
1482
0
      throw Exception("Missing parameter " _name, __FILE__, __LINE__);                                          \
1483
0
   }                                                                                                            \
1484
0
   return p->value();                                                                                           \
1485
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
1486
1487
defineParam(ob,"ob",ExistsParameter,"RFC 5626");
1488
defineParam(gr, "gr", ExistsOrDataParameter, "RFC 5627");
1489
defineParam(comp, "comp", DataParameter, "RFC 3486");
1490
defineParam(duration, "duration", UInt32Parameter, "RFC 4240");
1491
defineParam(lr, "lr", ExistsParameter, "RFC 3261");
1492
defineParam(maddr, "maddr", DataParameter, "RFC 3261");
1493
defineParam(method, "method", DataParameter, "RFC 3261");
1494
defineParam(transport, "transport", DataParameter, "RFC 3261");
1495
defineParam(ttl, "ttl", UInt32Parameter, "RFC 3261");
1496
defineParam(user, "user", DataParameter, "RFC 3261, 4967");
1497
defineParam(extension, "ext", DataParameter, "RFC 3966"); // Token is used when ext is a user-parameter
1498
defineParam(sigcompId, "sigcomp-id", QuotedDataParameter, "RFC 5049");
1499
defineParam(rinstance, "rinstance", DataParameter, "proprietary (resip)");
1500
defineParam(addTransport, "addTransport", ExistsParameter, "RESIP INTERNAL");
1501
defineParam(wsSrcIp, "ws-src-ip", DataParameter, "RESIP INTERNAL (WebSocket)");
1502
defineParam(wsSrcPort, "ws-src-port", UInt32Parameter, "RESIP INTERNAL (WebSocket)");
1503
1504
#undef defineParam
1505
1506
HashValueImp(resip::Uri, resip::Data::from(data).hash());
1507
1508
/* ====================================================================
1509
 * The Vovida Software License, Version 1.0 
1510
 * 
1511
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
1512
 * 
1513
 * Redistribution and use in source and binary forms, with or without
1514
 * modification, are permitted provided that the following conditions
1515
 * are met:
1516
 * 
1517
 * 1. Redistributions of source code must retain the above copyright
1518
 *    notice, this list of conditions and the following disclaimer.
1519
 * 
1520
 * 2. Redistributions in binary form must reproduce the above copyright
1521
 *    notice, this list of conditions and the following disclaimer in
1522
 *    the documentation and/or other materials provided with the
1523
 *    distribution.
1524
 * 
1525
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1526
 *    and "Vovida Open Communication Application Library (VOCAL)" must
1527
 *    not be used to endorse or promote products derived from this
1528
 *    software without prior written permission. For written
1529
 *    permission, please contact vocal@vovida.org.
1530
 *
1531
 * 4. Products derived from this software may not be called "VOCAL", nor
1532
 *    may "VOCAL" appear in their name, without prior written
1533
 *    permission of Vovida Networks, Inc.
1534
 * 
1535
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1536
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1537
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1538
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
1539
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1540
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1541
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1542
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1543
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1544
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1545
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1546
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1547
 * DAMAGE.
1548
 * 
1549
 * ====================================================================
1550
 * 
1551
 * This software consists of voluntary contributions made by Vovida
1552
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1553
 * Inc.  For more information on Vovida Networks, Inc., please see
1554
 * <http://www.vovida.org/>.
1555
 *
1556
 */